《java 多線程編程核心技術》讀書筆記三

背景知識補充:

  1. 局部變量是線程安全的,局部變量屬於線程私有的,在線程間不共享
  2. 類變量是非線程安全的,在多個實例之間、多個線程之間都是共享的
  3. 實例變量屬於對象,在多個對象間不共享,當多個線程操作同一個對象的實例變量時,該變量將在多個線程中共享,則會導致非線程安全問題,但當多個線程分別操作同一個類的不同對象時,該變量只存在於當前線程中,故不會導致非線程安全問題

爲了解決線程不安全的問題,java中提供了synchronized關鍵字,synchronized可以用於修飾方法或修飾代碼塊

synchronized 同步方法

其語法格式就是在方法前面加上synchronized關鍵字,如下:

synchronized public void methodName(){}

適用場景

當該方法內部有對共享資源進行讀寫操作時該方法就需要使用synchronized關鍵字修飾

synchronized取得的鎖是對象鎖,當一個線程調用對象的一個同步方法時,該線程將持有該對象的對象鎖,其它線程可以直接調用該對象中沒有被synchronized關鍵字修飾的方法,其它線程若要調用該對象中被synchronized關鍵字修飾的方法時,需要等待前一個線程釋放該對象的對象鎖後方可調用,在此之前只能排隊等待

如果多個線程訪問同一個類的多個對象,則JVM會創建多個鎖

這裏說的會創建多個鎖,那這些鎖是在什麼時候創建的呢?

鎖重入

前面背景知識提到當一個線程持有某個對象的對象鎖時,其它線程若想獲得該對象的對象鎖則需要等待前一個線程釋放對象鎖後纔可以獲得。

現在我們來分析一個例子
有個類中含有兩個被synchronized關鍵字修飾的方法,分別爲methodA、methodB,methodA中調用methodB,此時程序還能正常執行嗎?

public class Services {
    synchronized public static void methodA(){
        System.out.println("methodA");
        new Services().methodB();
    }

    synchronized public void methodB(){
        System.out.println("methodB");
        methodC();
    }

    synchronized public void methodC(){
        System.out.println("methodC");

    }
}

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        Services services = new Services();
        services.methodA();
    }
}

public class Run {
    public static void main(String[] args){
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

這裏涉及到鎖重入的概念,那什麼是鎖重入呢?
當一個線程得到某對象的對象鎖後,在還未釋放該對象鎖時該線程再次請求獲取該對象的對象鎖,是可以再次得到該對象的對象鎖。即synchronized方法、synchronized代碼塊的內部調用本類的其它synchronized方法、synchronized代碼塊時,是永遠可以得到對象鎖的。
鎖重入也適用於有父子關係的繼承類中

鎖釋放

當synchronized方法、synchronize代碼塊執行完畢後該線程持有的對象鎖將自動釋放,除此之外,當synchronized方法、synchronized代碼塊中出現異常時,該線程持有的對象鎖也將自動釋放

synchronized關鍵字不具有繼承性

父類中的synchronized方法在子類中重寫時去掉了synchronized關鍵字,則子類中的該方法不具有同步功能

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