JAVA synchronized同步塊

Java 中同步關鍵字(synchronized

Java語言的關鍵字,可用來給對象和方法或者代碼塊加鎖,當它鎖定一個方法或者一個代碼塊的時候,同一時刻最多隻有一個線程執行這段代碼。當兩個併發線程訪問同一個對象object中的這個加鎖同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。然而,當一個線程訪問object的一個加鎖代碼塊時,另一個線程仍可以訪問該object中的非加鎖代碼塊。


這夠同步麼!

4種不同類型的同步塊

  • 實例同步方法
  • 類(靜態)同步方法
  • 實例方法中的同步代碼塊
  • 類(靜態)方法中的同步代碼塊
實例同步方法

synchronized 關鍵字使用在實例方法上,也就是對象方法,一個 new 出來的對象的方法上使用了 synchronized 關鍵修飾,那麼這個方法就是同步方法,針對這個對象調用該同步方法時,每次只允許一個線程調用該同步方法,當有其他線程調用這個同步方法時,將被阻塞,直到上一個線程將結果刷新到主內存完全退出時,其他線程才能調用該同步方法,保證了線程安全性。

public class MySynchronized {

    int value = 0 ;

    public synchronized void add(int value) {
        this.value += value;
    }
}

測試:

public void add(int value) {
    this.value += value;
}

先去除synchronized關鍵字,由於直接new Thread操作沒辦法保證主線程運行完時其他線程也運行完成,所以我這裏使用了java 8中的並行流模擬多線程操作。

@Test
public void test1() throws InterruptedException {
    MySynchronized mySynchronized = new MySynchronized();

    ArrayList<Integer> nums = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        nums.add(1);
    }
    nums.parallelStream().forEach(num -> mySynchronized.add(num));

    System.out.println(mySynchronized.value);
}

多運行幾次可以看出結果並不時我們預想的1000,再次測試加上synchnized關鍵字之後的結果。

public synchronized void add(int value) {
    this.value += value;
}

每次執行的結果都是符合預期1000。這裏同步的對象是this

實例中的同步代碼塊
public class MySynchronized {

    int value = 0;

    public void add(int value) {
        synchronized (this) {
            this.value += value;
        }
    }
}

當方法中只有一部分代碼需要保證線程安全時,就可以使用同步代碼塊,作用與同步方法基本相同,這裏我們使用的是this對象來同步,this代表的是調用這個方法的實例對象,如果實例A的同步方法add()無法同步實例B的add()方法

靜態同步方法
public class MySynchronized {

    static int value = 0;

    public static synchronized void add(int value) {
        value = value;
    }
}

使用staticsynchronized關鍵字共同修飾的方法。針對類對象的同步,同一時間只能有一個線程調用靜態同步方法,同一個類對象在java虛擬機中只能有一個。同步的對象是MySynchronized.class

靜態方法中的同步方法塊
public class MySynchronized {

    static int value = 0;

    public static void add2(int value) {

        synchronized (MySynchronized.class) {
            value = value;
        }
    }
}

和靜態同步方法類似,這裏我使用的同步對象是MySynchronized.class,當然我們也可以使用其他對象來實現同步。

注意:如果一個同步方法調用另一個同步方法,同時使用的同步對象爲同一個對象,則這個兩個同步方法同時只能被一個線程調用。

參考:

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