欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中關(guān)鍵字synchronized的使用方法詳解

 更新時間:2021年08月13日 09:23:20   作者:超新星燃燒  
synchronized關(guān)鍵字可以作為函數(shù)的修飾符,也可作為函數(shù)內(nèi)的語句,也就是平時說的同步方法和同步語句塊,下面這篇文章主要給大家介紹了關(guān)于Java中synchronized使用的相關(guān)資料,需要的朋友可以參考下

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

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();
        //等待兩個線程結(jié)束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

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

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

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();
        //等待兩個線程結(jié)束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

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

使用synchronized 就相當(dāng)于在我們執(zhí)行的指令里又加入了2條新指令。

LOCK (加鎖)

UNLOCK (解鎖)

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

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

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

舉個例子:

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

synchronized 也會禁止編譯器進(jìn)行“內(nèi)存可見性”和“指令重排序”的優(yōu)化~ 同時程序運行的效率就會降低,
也會導(dǎo)致線程之間相互去等待,就涉及到系統(tǒng)的一些調(diào)度,也會引入一些時間成本。

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

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

public class TestDemo{
    public void methond() {
        // 進(jìn)入代碼塊會鎖 this 指向?qū)ο笾械逆i;
        // 出代碼塊會釋放 this 指向的對象中的鎖
        synchronized (this) {

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

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

public class TestDemo{
    public synchronized void methond() {

    }
    public static void main(String[] args) {
        TestDemo demo = new TestDemo();
        demo.methond();
        // 進(jìn)入方法會鎖 demo 指向?qū)ο笾械逆i;
        // 出方法會釋放 demo 指向的對象中的鎖
    }
}

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

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

    }
    public static void main(String[] args) {
        methond();
        // 進(jìn)入方法會鎖 TestDemo.class 指向?qū)ο笾械逆i;
        //出方法會釋放 TestDemo.class 指向的對象中的鎖
    }
}

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

public class TestDemo{
    public static void methond() {
        // 進(jìn)入代碼塊會鎖 TestDemo.class 指向?qū)ο笾械逆i;
        //出代碼塊會釋放 TestDemo.class 指向的對象中的鎖
        synchronized (TestDemo.class) {

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

總結(jié):

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

拓展:

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();
        //等待兩個線程結(jié)束
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

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

但是運行代碼發(fā)現(xiàn)程序依然正確運行?? 為什么

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

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

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

synchronized 內(nèi)部記錄了當(dāng)前這把鎖是哪個線程持有的~

如果當(dāng)前加鎖線程和持有鎖的線程是同一個線程~

此時就并不是真的進(jìn)行“加鎖操作”,而是把一個計數(shù)器加一;

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

如果該線程調(diào)用解鎖操作,也不是立刻就解鎖,而是計數(shù)器減1

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

總結(jié)

到此這篇關(guān)于Java中synchronized使用的文章就介紹到這了,更多相關(guān)Java中synchronized用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot實現(xiàn)類似鉤子函數(shù)的方法

    SpringBoot實現(xiàn)類似鉤子函數(shù)的方法

    這篇文章主要給大家介紹了關(guān)于SpringBoot實現(xiàn)類似鉤子函數(shù)的方法,文中通過代碼示例介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-04-04
  • Java springboot yaml語法注解

    Java springboot yaml語法注解

    這篇文章主要介紹了SpringBoot中的yaml語法及靜態(tài)資源訪問問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • 詳解Spring注解 @Configuration

    詳解Spring注解 @Configuration

    @Configuration 是 Spring 中的一個注解,它用于標(biāo)記一個類為配置類,通過配置類可以定義和組裝 Spring Bean,并且支持高度靈活的配置方式。本問詳細(xì)介紹了Spring注解 @Configuration,感興趣的小伙伴可以參考一下
    2023-04-04
  • Java人機(jī)猜拳實現(xiàn)的思路及方法實例

    Java人機(jī)猜拳實現(xiàn)的思路及方法實例

    這篇文章主要給大家介紹了關(guān)于Java人機(jī)猜拳實現(xiàn)的思路及方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Spring Boot 整合 Shiro+Thymeleaf過程解析

    Spring Boot 整合 Shiro+Thymeleaf過程解析

    這篇文章主要介紹了Spring Boot 整合 Shiro+Thymeleaf過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • 深入Java對象的地址的使用分析

    深入Java對象的地址的使用分析

    本篇文章介紹了,Java對象的地址的使用分析。需要的朋友參考下
    2013-05-05
  • 詳解用JWT對SpringCloud進(jìn)行認(rèn)證和鑒權(quán)

    詳解用JWT對SpringCloud進(jìn)行認(rèn)證和鑒權(quán)

    這篇文章主要介紹了詳解用JWT對SpringCloud進(jìn)行認(rèn)證和鑒權(quán),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Mybatis Plus使用@TableId的示例詳解

    Mybatis Plus使用@TableId的示例詳解

    在 MyBatis Plus 中,@TableId 注解是用于標(biāo)記實體類中的主鍵字段,它可以更方便地處理主鍵相關(guān)的操作,如自動填充主鍵值或識別主鍵字段,這篇文章主要介紹了Mybatis Plus使用@TableId,需要的朋友可以參考下
    2024-08-08
  • jar包雙擊執(zhí)行程序的方法

    jar包雙擊執(zhí)行程序的方法

    這篇文章主要介紹了jar包雙擊執(zhí)行程序的方法,可實現(xiàn)雙擊jar包直接執(zhí)行Java程序的功能,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-12-12
  • mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值

    mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值

    這篇文章主要介紹了mybatis實現(xiàn)獲取入?yún)⑹荓ist和Map的取值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06

最新評論