併發編程(叄):synchronize

synchronize


synchronized是Java中的關鍵字,是一種經常使用的線程同步鎖。

用法

注意:在理解synchronized時,要知道一個核心點,synchronized鎖定的不是代碼,而是對象。使用synchronized時,其會申請對象的堆內存,進行鎖定。java

寫法一

Object o = new Object(); // 鎖對象
    public void test01(){
        //任何線程要執行如下的代碼,必須先拿到鎖
        synchronized (o){  
            // doSomething...
        }
    }

寫法二

上述寫法是建立一個鎖對象,其實能夠自身做爲鎖對象。安全

public void test02(){
        synchronized (this){ 
            // doSomething...
        }
    }

寫法三

同寫法二。ide

public synchronized void test03(){
        // doSomething...
    }

寫法四

鎖定靜態方法。靜態方法是屬於類方法,沒有對象。測試

public synchronized static void test04(){
    }

寫法五

同寫法四this

public static void test04(){
        synchronized (SynchronizeTest.class){
        }
    }

測試線程安全問題

演示代碼:線程

public class RunnableDemo implements Runnable {

    private int count = 10;

    @Override
    public /*synchronized*/ void run() {
        count--;
        System.out.println(Thread.currentThread().getName() + "count=" + count);
    }

    public static void main(String[] args) {
        RunnableDemo t = new RunnableDemo();
        for (int i = 0; i < 8; i++) {
            new Thread(t, "結果是:" + i).start();
        }
    }
}

結果是:調試

結果是:1count=9
結果是:0count=8
結果是:2count=7
結果是:3count=6
結果是:5count=5
結果是:4count=4
結果是:6count=3
結果是:7count=2

加入synchronized:code

結果是:0count=9
結果是:1count=8
結果是:2count=7
結果是:3count=6
結果是:4count=5
結果是:5count=4
結果是:6count=3
結果是:7count=2

能夠看到輸出順序是不同的.對象

注意事項

在實際業務場景中,每每將讀方法不加鎖,寫的方法加鎖,這樣會致使一個問題,也就是讀的數據是寫以前的數據,致使髒讀問題。解決方案就是,在讀方法上也加鎖內存

  1. 加鎖方法不影響不加鎖方法的執行;

  2. 加鎖方法訪問另一個加鎖方法,一個線程擁有某個對象的鎖,再次申請的時候能夠再次獲得這把鎖(至關於鎖上了兩把一樣的鎖);子類的同步方法調用父類的同步方法也能夠;

  3. synchronized 遇到異常,鎖會被釋放。若是不想該鎖被釋放,就直接catch;

  4. 不要以字符串常量做爲鎖對象。
public class StringAsSynchObject {
    private String stra = "hello";
    private String strb = "hello";
    void test1(){
        synchronized (stra){
        }
    }
    void test2(){
        synchronized (strb){
        }
    }
}

在上述代碼中,由於stra和strb 鎖的是同一個對象,若是用到了同一個類庫,在該類庫中的代碼鎖定了字符串"hello",咱們讀不到源碼,而在業務代碼中也鎖定了一樣的字符串,這就有可能會形成很是詭異的死鎖阻塞。由於程序和類庫不經意用了同一把鎖。(這種狀況通常沒辦法調試)。因此一般不要字符串做爲鎖定對象。

  1. synchronize 鎖定的粒度越小(即鎖定的業務代碼越少),效率越高。
  2. synchronize 鎖釋放的狀況:

    1)線程執行完畢;

    2)線程發生異常;

    3)線程進入休眠狀態。
  3. synchronize 是互斥鎖,可重入鎖。
  4. wait()和notify()/notifyAll() 與 synchronize同時出現。

相關文章
相關標籤/搜索