一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中關鍵字synchronized的使用方法詳解

Java中關鍵字synchronized的使用方法詳解

2021-11-17 13:03超新星燃燒 Java教程

synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊,下面這篇文章主要給大家介紹了關于Java中synchronized使用的相關資料,需要的朋友可以參考下

synchronizedJava里的一個關鍵字,起到的一個效果是“監視器鎖”~~,它的功能就是保證操作的原子性,同時禁止指令重排序和保證內存的可見性!

public  class TestDemo {
    static  class Counter{
        public int count = 0;

        public void add(){
            count++;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    counter.add();
                }
            }
        };

        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    counter.add();
                }
            }
        };

        //啟動兩個線程
        t1.start();
        t2.start();
        //等待兩個線程結束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

Java中關鍵字synchronized的使用方法詳解

此時的線程就是不安全的,如何解決呢?

給我們的Counter對象里的add方法加上synchronized關鍵字,針對這個方法進行了加鎖操作。進入代碼塊(調用方法)自動加鎖,出了代碼塊(方法結束),自動解鎖。

public  class TestDemo {
    static  class Counter{
        public int count = 0;
         
         //修飾方法
         synchronized public void add{
             count++;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    counter.add();
                }
            }
        };

        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    counter.add();
                }
            }
        };

        //啟動兩個線程
        t1.start();
        t2.start();
        //等待兩個線程結束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

Java中關鍵字synchronized的使用方法詳解

那么這里的代碼是如何保證正確的呢?

使用synchronized 就相當于在我們執行的指令里又加入了2條新指令。

LOCK (加鎖)

UNLOCK (解鎖)

LOCK操作特性:只有一個線程能執行成功!如果第一個線程執行成功,第二個線程也嘗試LOCK,就會阻塞等待,直到第一個線程執行UNLOCK 釋放鎖~

Java中關鍵字synchronized的使用方法詳解

通過LOCK和UNLOCK 就把 LOAD ADD SAVE 這三個指令,給打包成了一個原子的操作(中間不能被打斷,也不能被其他線程穿插)。

這里的加鎖也是保證原子性的核心操作,所以線程里的沒組指令就會順序執行,不在穿插執行,就保證了線程1執行完之后再去執行線程2。

舉個例子:

就好比張三和李四去ATM里去取錢,當張三進去取錢時,進去后就會鎖門,李四就會在外面等待,直到張三取完錢出來后,李四在進去取錢。

synchronized 也會禁止編譯器進行“內存可見性”和“指令重排序”的優化~ 同時程序運行的效率就會降低,
也會導致線程之間相互去等待,就涉及到系統的一些調度,也會引入一些時間成本。

synchronized修飾的對象有以下幾種:

修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;

public class TestDemo{
    public void methond() {
        // 進入代碼塊會鎖 this 指向對象中的鎖;
        // 出代碼塊會釋放 this 指向的對象中的鎖
        synchronized (this) {

        }
    }
    public static void main(String[] args) {
        TestDemo demo = new TestDemo();
        demo.methond();
    }
}

修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;

public class TestDemo{
    public synchronized void methond() {

    }
    public static void main(String[] args) {
        TestDemo demo = new TestDemo();
        demo.methond();
        // 進入方法會鎖 demo 指向對象中的鎖;
        // 出方法會釋放 demo 指向的對象中的鎖
    }
}

修改一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;

public class TestDemo{
    public synchronized static void methond() {

    }
    public static void main(String[] args) {
        methond();
        // 進入方法會鎖 TestDemo.class 指向對象中的鎖;
        //出方法會釋放 TestDemo.class 指向的對象中的鎖
    }
}

修改一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象。

public class TestDemo{
    public static void methond() {
        // 進入代碼塊會鎖 TestDemo.class 指向對象中的鎖;
        //出代碼塊會釋放 TestDemo.class 指向的對象中的鎖
        synchronized (TestDemo.class) {

        }
    }
    public static void main(String[] args) {
        TestDemo demo = new TestDemo();
        demo.methond();
    }
}

總結:

  • 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;
  • 如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
  • 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
  • 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。

拓展:

public  class TestDemo {

    static   class Counter{
        public int count = 0;

           public void add(){
               synchronized (this){
                   count++;
               }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    synchronized (counter){
                        counter.add();
                    }
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    synchronized (counter){
                        counter.add();
                    }
                }
            }
        };

        //啟動兩個線程
        t1.start();
        t2.start();
        //等待兩個線程結束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

此時可以看出上述代碼,加了兩次鎖,會發生什么呢?

Java中關鍵字synchronized的使用方法詳解

Java中關鍵字synchronized的使用方法詳解

但是運行代碼發現程序依然正確運行?? 為什么

但是上述分析死鎖的思路是對的

只是因為synchronized內部使用特殊手段來處理了這種情況 。

這樣的操作特性我們叫做 可重入鎖

synchronized 內部記錄了當前這把鎖是哪個線程持有的~

如果當前加鎖線程和持有鎖的線程是同一個線程~

此時就并不是真的進行“加鎖操作”,而是把一個計數器加一;

如果后續該線程繼續嘗試獲取鎖,繼續判定加鎖線程和持有鎖線程是不是同一個線程,只要是同一個線程,就不真的加鎖,而是計數器+1;

如果該線程調用解鎖操作,也不是立刻就解鎖,而是計數器減1

直到計數器減成0了,才認為真的要“釋放鎖”,才允許其他線程來獲取鎖~~

總結

到此這篇關于Java中synchronized使用的文章就介紹到這了,更多相關Java中synchronized用法內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/wlm123666/article/details/119580473

延伸 · 閱讀

精彩推薦
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
主站蜘蛛池模板: 肉文高h调教 | 91久久精品国产一区二区 | 好大好硬好深好爽想要小雪 | 精品女同一区二区三区免费站 | 成人免费在线视频观看 | 青春娱乐国产分类精品二 | 国产不卡视频一区二区在线观看 | 极品美女写真菠萝蜜视频 | jizzjizz3d动漫| 波多野结衣 在线 | yellow视频在线观看免费 | 亚洲免费在线观看视频 | 好大用力深一点视频 | 国产一二在线观看视频网站 | 国产资源免费观看 | 免费观看小视频 | 欧美成狂野欧美在线观看 | 热国产热综合 | 国产精品秒播无毒不卡 | 国产综合色在线视频区色吧图片 | 青青久久久国产线免观 | 午夜理论片日本中文在线 | 国产日韩欧美视频 | 免费在线影院 | 亚洲成年人在线观看 | 久久国产精品永久免费网站 | coolgay男男gayxxx chinese壮直男gay老年人 chinese野外gay军人 | 亚洲精品免费观看 | 美女张开大腿让男人桶 | 亚洲国产精品久久久久久 | 精品老司机在线视频香蕉 | 日本mv精品中文字幕 | 日韩视频一区二区 | 四虎在线播放 | 俄罗斯妈妈k8影院在线观看 | 日韩中文字幕视频在线观看 | 特黄特黄一级高清免费大片 | 精新精新国产自在现 | 明星h文集合短篇小说 | 亚洲国产美女精品久久 | 娇妻被健身教练挺进小说阅读 |