Java synchronized&volatile

synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區,同時它還可以保證共享變量的內存可見性

Java中每一個對象都可以作爲鎖,這是synchronized實現同步的基礎:

  1. 普通同步方法,鎖是當前實例對象;
  2. 靜態同步方法,鎖是當前類的class對象;
  3. 同步方法塊,鎖是括號裏面的對象。

1. synchronized對象鎖

synchronized可以修飾實例方法,主要有兩種:

public class MyObject {

     synchronized public void methodA() {
         //do something....
     }
public class MyObject {

    public void methodA() {
        synchronized(this){
            //do something....
        }
    }

synchronized 關鍵字鎖住的是當前對象。這也是稱爲對象鎖的原因。

2. 線程間通訊

傳統的線程通信可以藉助Object類提供的wait() notify() notifyAll()三個方法實現:

  1. wait():導致當前線程等待,直到其他線程調用該同步監視器的notify()方法或notifyAll()方法來喚醒線程,調用wait()方法的當前線程會釋放對該同步監視器的鎖定;

  2. notify():喚醒在此同步監視器上等待的單個線程,如果所有線程都在此同步監視器上等待,則會選擇喚醒其中一個線程(選擇是任意性的)。只有當前線程放棄對該同步監視器的鎖定後(使用wait()方法),纔可以執行被喚醒的線程;

  3. notifyAll():喚醒在此同步監視器上等待的所有線程,只有當前線程放棄對該同步監視器的鎖定後(使用wait()方法),纔可以執行被喚醒的線程;

  • 對於使用synchronized修飾的同步方法,因爲該類的默認實例(this)就是同步監視器,所以可以在同步方法中直接調用這三個方法;
  • 對於使用synchronized修飾的同步代碼塊,同步監視器是synchronized後括號裏的對象,所以必須使用該對象調用者三個方法。

3. volatile

  • volatile保證多線程共享變量可見性。
  • 禁止指令重排序
  • 不保證原子性

volatile 定義的變量,特殊性在於:

一個線程對 volatile 變量的寫一定對之後對這個變量的讀的線程可見。

即:

一個線程對 volatile 變量的讀一定能看見在它之前最後一個線程對這個變量的寫。

4. volatile 和 synchronized比較

  1. 當線程對 volatile變量寫時,java 會把值刷新到共享內存中;而對於synchronized,指的是當線程釋放鎖的時候,會將共享變量的值刷新到主內存中。

  2. 線程讀取volatile變量時,會將本地內存中的共享變量置爲無效;對於synchronized來說,當線程獲取鎖時,會將當前線程本地內存中的共享變量置爲無效。

  3. synchronized 擴大了可見影響的範圍,擴大到了synchronized作用的代碼塊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章