中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Synchronized怎么用

發布時間:2021-11-17 11:01:40 來源:億速云 閱讀:214 作者:小新 欄目:大數據

小編給大家分享一下Synchronized怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

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

Java中每一個對象都可以作為鎖,這是synchronized實現同步的基礎: 
1. 普通同步方法,鎖是當前實例對象 
2. 靜態同步方法,鎖是當前類的class對象 
3. 同步方法塊,鎖是括號里面的對象

synchronized 獲取的鎖,在方法拋出異常的時候會自動解鎖 

實現原理

利用javap工具查看生成的class文件信息來分析Synchronize的實現 

Synchronized怎么用
從上面可以看出,同步代碼塊是使用monitorenter和monitorexit指令實現的,同步方法(在這看不出來需要看JVM底層實現)依靠的是方法修飾符上的ACC_SYNCHRONIZED實現。 
同步代碼塊:monitorenter指令插入到同步代碼塊的開始位置,monitorexit指令插入到同步代碼塊的結束位置,JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何對象都有一個monitor與之相關聯,當且一個monitor被持有之后,他將處于鎖定狀態。線程執行到monitorenter指令時,將會嘗試獲取對象所對應的monitor所有權,即嘗試獲取對象的鎖; 
同步方法:synchronized方法則會被翻譯成普通的方法調用和返回指令如:invokevirtual、areturn指令,在VM字節碼層面并沒有任何特別的指令來實現被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags字段中的synchronized標志位置1,表示該方法是同步方法并使用調用該方法的對象或該方法所屬的Class在JVM的內部對象表示Klass做為鎖對象。

同步方法和同步代碼塊


同步方法就是在方法前加關鍵字synchronized,然后被同步的方法一次只能有一個線程進入,其他線程等待。
而同步塊則是在方法內部使用大括號使得一個代碼塊得到同步。同步塊會有一個同步的”目標“,使得同步塊更加靈活一些(同步塊可以通過”目標“決定需要鎖定的對象)。一般情況下,如果此”目標“為this,那么同步方法和同步塊沒有太大的區別。

對象鎖和類鎖的區別

synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態方法前面是給對象上鎖。這兩者的區別我用代碼來演示下:

對象鎖和類鎖是不同的鎖,所以多個線程同時執行這2個不同鎖的方法時,是異步的。
在Task2 中定義三個方法 doLongTimeTaskA和doLongTimeTaskB是類鎖,而doLongTimeTaskC是對象鎖。

public class Task2 {

    public synchronized static void doLongTimeTaskA() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized static void doLongTimeTaskB() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized void doLongTimeTaskC() {

        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");

    }

三個線程的代碼如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskB();
    }
}

class ThreadC extends Thread{

    private Task2 mTask2;

    public ThreadC(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main函數中執行代碼如下:

        Task2 mTask2 = new Task2();
        ThreadA ta = new ThreadA(mTask2);
        ThreadB tb = new ThreadB(mTask2);
        ThreadC tc = new ThreadC(mTask2);

        ta.setName("A");
        tb.setName("B");
        tc.setName("C");

        ta.start();
        tb.start();
        tc.start();
}
執行的結果如下:

name = A, begain, time = 1487311199783
name = C, begain, time = 1487311199783
name = C, end, time = 1487311200784
name = A, end, time = 1487311200784
name = B, begain, time = 1487311200784
name = B, end, time = 1487311201784

可以看出由于 doLongTimeTaskA和doLongTimeTaskB都是類鎖,即同一個鎖,所以 A和B是按順序執行,即同步的。而C是對象鎖,和A/B不是同一種鎖,所以C和A、B是 異步執行的。(A、B、C代指上面的3中方法)。

我們知道對象鎖要想保持同步執行,那么鎖住的必須是同一個對象。下面就修改下上面的來證明:

Task2.java不變,修改ThreadA 和 ThreadB 如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main方法如下:

 Task2 mTaska = new Task2();
 Task2 mTaskb = new Task2();
 ThreadA ta = new ThreadA(mTaska );
 ThreadB tb = new ThreadB(mTaskb );


 ta.setName("A");
 tb.setName("B");

 ta.start();
 tb.start();

結果如下:

name = A, begain, time = 1487311905775
name = B, begain, time = 1487311905775
name = B, end, time = 1487311906775
name = A, end, time = 1487311906775

從結果看來,對象鎖鎖的對象不一樣,分別是mTaska , mTaskb,所以線程A和線程B調用 doLongTimeTaskC 是異步執行的。

但是,類鎖可以對類的所有對象的實例起作用。只需修改ThradA 
和 ThreadB,main 方法不做改變,修改如下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
       //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

結果如下:

name = A, begain, time = 1487312239674
name = A, end, time = 1487312240674
name = B, begain, time = 1487312240674
name = B, end, time = 1487312241674

可以看出 在線程A執行完doLongTimeTaskA方法后,線程B才會獲得該類鎖接著去執行doLongTimeTaskA。也就是說,類鎖對所有的該類對象都能起作用。

總結: 
1. 如果多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是異步的,原因:類鎖和對象鎖是2中不同的鎖。 
2. 類鎖對該類的所有對象都能起作用,而對象鎖不能。

synchronized可重入鎖的實現

之前談到過,每個鎖關聯一個線程持有者和一個計數器。當計數器為0時表示該鎖沒有被任何線程持有,那么任何線程都都可能獲得該鎖而調用相應方法。當一個線程請求成功后,JVM會記下持有鎖的線程,并將計數器計為1。此時其他線程請求該鎖,則必須等待。而該持有鎖的線程如果再次請求這個鎖,就可以再次拿到這個鎖,同時計數器會遞增。當線程退出一個synchronized方法/塊時,計數器會遞減,如果計數器為0則釋放該鎖。

以上是“Synchronized怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

佛坪县| 新乡市| 广昌县| 镇远县| 临漳县| 信丰县| 正定县| 托里县| 合川市| 山西省| 南木林县| 成武县| 囊谦县| 中山市| 桦川县| 南投市| 武平县| 江口县| 买车| 苏州市| 台州市| 湘潭市| 水城县| 资中县| 青铜峡市| 屯门区| 宜兰市| 固原市| 清远市| 沅江市| 阜阳市| 如皋市| 石狮市| 金秀| 阆中市| 江安县| 农安县| 千阳县| 万载县| 酒泉市| 南澳县|