線程安全之同步方法
當(dāng)線程共享一個資源時會由于互搶cup而造成對資源的操作不安全問題,所以要用同步方法或同步代碼塊進行代碼同步處理操作,保證線程安全
同步代碼塊
synchronized(Object o){
}
將要進行的代碼放入大括號內(nèi),小括號內(nèi)放資源類對象,也被稱為:鎖,
一旦有線程進入了大括號在執(zhí)行完最后一行代碼之前,其他線程是進不來的
所以保證了在一個線程對一個資源進行操作完成之前不會有別的線進來搶,從而保證了線程的安全.
package com.qf.demo;
public class Test {
public static void main(String[] args) {
Window window = new Window();
Thread thread = new Thread(window,"二狗");
Thread thread2 = new Thread(window,"三狗");
Thread thread3 = new Thread(window,"四狗");
Thread thread4 = new Thread(window,"五狗");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
* 使用同步代碼塊
* 1 確定要被同步的代碼
* 2 用同步代碼塊 將要被同步的代碼進行同步
* synchronized(object){
* 被同步的代碼
* }
* @author Administrator
*
*/
class Window implements Runnable{
int ticket= 100;
//Window object = new Window();// 鎖的對象必須是唯一的 多個線程 公用一把鎖
// 如果是多把鎖, 就相當(dāng)于沒加鎖
// 資源類 只能創(chuàng)建一個對象, 可以利用資源類對象 this
@Override
public void run() {
while(true){
synchronized (this) {// 鎖是object 任意類型的 任意鎖, 互斥鎖
if(ticket>0){
ticket--;
try {
Thread.sleep(1000);// 會釋放cpu , 但是沒有釋放鎖資源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"賣了1張票,還剩"+ticket);
}else{
break;
}
}
}
}
}
同步方法
public synchronized void printNumber(int num){
}
同步方法要寫在資源類內(nèi)部,而且要求鎖是唯一的,所以鎖用this來調(diào)用
package com.qf.demo;
public class Test3 {
public static void main(String[] args) {
Window2 window2 = new Window2();
Thread thread = new Thread(window2,"馬什么梅");
Thread thread2 = new Thread(window2,"什么冬梅");
Thread thread3= new Thread(window2,"馬東什么");
Thread thread4 = new Thread(window2,"馬冬梅啊");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
/**
* 同步方法
*
* @author Administrator
*
*/
class Window2 implements Runnable {
int ticket = 100;
@Override
public void run() {// 不要在run 方法上面添加synchronized
while (true) {
if(!saleTicket()){
break;
}
}
}
// 同步方法 鎖是 this 還要要求 鎖是 唯一的 , 同步方法要寫在資源類里面
public synchronized boolean saleTicket(){
if (ticket > 0) {
ticket--;
try {
Thread.sleep(1000);// 會釋放cpu , 但是沒有釋放鎖資源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "賣了1張票,還剩" + ticket);
return true;
} else{
return false;
}
}
}
懶漢模式
之前說過懶漢模式是線程不安全的,現(xiàn)在我們對他進行改造一下就可以變成線程安全的
package com.qf.demo2;
public class LazyInstance {
private LazyInstance(){
}
private static LazyInstance instance;
// 加上一個同步代碼塊或者是同步方法 就是能實現(xiàn) 線程安全的單例
public static LazyInstance getInstance(){
// 雙重檢查, 雙重鎖
if(instance == null){// 為了 防止所有的線程都要去判斷鎖,
//盡可能少的讓線程判斷鎖, 就可以調(diào)高效率
synchronized (LazyInstance.class) {
if(instance==null){
//線程一 null 并且沒有創(chuàng)建對象
// 線程二 null 創(chuàng)建對象了
instance = new LazyInstance();
}
}
}
return instance;
}
public static synchronized void a(){
if(instance==null){
//線程一 null 并且沒有創(chuàng)建對象
// 線程二 null 創(chuàng)建對象了
instance = new LazyInstance();
}
}
}