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

Java多線程之synchronized同步代碼塊詳解

 更新時間:2022年03月02日 10:36:49   作者:小小茶花女  
這篇文章主要為大家詳細介紹了Java多線程之synchronized同步代碼塊,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

面試題:

1同步方法和同步塊,哪種更好?

2.如果同步塊內(nèi)的線程拋出異常會發(fā)生什么?

1. 同步方法和同步塊,哪種更好?

同步塊更好,這意味著同步塊之外的代碼是異步執(zhí)行的,這比同步整個方法更提升代碼的效率。請知道一條原則:同步的范圍越小越好。

對于小的臨界區(qū),我們直接在方法聲明中設(shè)置synchronized同步關(guān)鍵字,可以避免競態(tài)條件的問題。但是對于較大的臨界區(qū)代碼段,為了執(zhí)行效率,最好將同步方法分為小的臨界區(qū)代碼段。

public class TwoPlus {
    private int num1 = 0;
    private int num2 = 0;
    public synchronized void plus(int val1,int val2){
        this.num1 = num1+val1;
        this.num2 = num2+val2;
    }
}

臨界區(qū)代碼段包含對兩個臨界區(qū)資源的操作,這兩個臨界區(qū)資源分別為sum1和sum2。使用synchronized對plus(int val1,int val2)進行同步保護之后,進入臨界區(qū)代碼段的線程擁有sum1和sum2的操作權(quán),并且是全部占用。一旦線程進入,當線程在操作sum1而沒有操作sum2時,也將sum2的操作權(quán)白白占用,其他的線程由于沒有進入臨界區(qū),只能看著sum2被閑置而不能去執(zhí)行操作。

所以,將synchronized加在方法上,如果其保護的臨界區(qū)代碼段包含的臨界區(qū)資源多于一個,就會造成臨界區(qū)資源的閑置等待,進而會影響臨界區(qū)代碼段的吞吐量。為了提升吞吐量,可以將synchronized關(guān)鍵字放在函數(shù)體內(nèi),同步一個代碼塊。synchronized同步塊的寫法是:

synchronized (syncObject){
    // 臨界區(qū)代碼段的代碼塊
}

在synchronized同步塊后邊的括號中是一個syncObject對象,代表著進入臨界區(qū)代碼段需要獲取syncObject對象的監(jiān)視鎖,由于每一個Java對象都有一把監(jiān)視鎖,因此任何Java對象都能作為synchronized的同步鎖。

使用synchronized同步塊對上面的TwoPlus類進行吞吐量的提升改造,具體的代碼如下:

public class TwoPlus {
    private int num1 = 0;
    private int num2 = 0;
    // 兩把不同的鎖對象
    private Object object1 = new Object();
    private Object object2 = new Object();
    public  void plus(int val1,int val2){
        synchronized (object1){
            this.num1 = num1+val1;
        }
        synchronized (object2){
            this.num2 = num2+val2;
        }
    }
}

改造之后,對兩個獨立的臨界區(qū)資源sum1和sum2的加法操作可以并發(fā)執(zhí)行了,在某一個時刻,不同的線程可以對sum1和sum2同時進行加法操作,提升了plus()方法的吞吐量。

synchronized方法和synchronized同步塊有什么區(qū)別呢?

總體來說,synchronized方法是一種粗粒度的并發(fā)控制,某一時刻只能有一個線程執(zhí)行該synchronized方法;而synchronized代碼塊是一種細粒度的并發(fā)控制,處于synchronized塊之外的其他代碼是可以被多個線程并發(fā)訪問的。在一個方法中,并不一定所有代碼都是臨界區(qū)代碼段,可能只有幾行代碼會涉及線程同步問題。所以synchronized代碼塊比synchronized方法更加細粒度地控制了多個線程的同步訪問。

synchronized方法的同步鎖實質(zhì)上使用了this對象鎖,這樣就免去了手工設(shè)置同步鎖的工作。而使用synchronized代碼塊需要手工設(shè)置同步鎖。

2. synchronized同步代碼塊

public class RoomDemo {
    private static int count = 0;
    // 創(chuàng)建鎖對象,同步代碼塊需要手動設(shè)置對象鎖
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for(int i=0;i<5000;i++){
                // 使用object對象鎖住臨界區(qū)資源
                synchronized (object){
                    count++;
                }
            }
        },"t1");
        Thread t2 = new Thread(()->{
            // 使用object對象鎖住臨界區(qū)資源
            for(int i=0;i<5000;i++){
                synchronized (object){
                    count--;
                }
            }
        },"t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);// 0
    }
}

在這里插入圖片描述

你可以做這樣的類比: synchronized(對象) 中的對象,可以想象為一個房間,線程 t1,t2 想象成兩個人

(1) 當線程 t1 執(zhí)行到 synchronized(object) 時就好比 t1 進入了這個房間,并鎖住了門拿走了鑰匙,在門內(nèi)執(zhí)行 count++ 代碼 ;

(2) 這時候如果 t2 也運行到了 synchronized(object) 時,它發(fā)現(xiàn)門被鎖住了,只能在門外等待,發(fā)生了上下文切換,阻塞住了 ;

(3) 這中間即使 t1 的 cpu 時間片不幸用完,被踢出了門外 (不要錯誤理解為鎖住了對象就能一直執(zhí)行下去哦) , 這時門還是鎖住的,t1 仍拿著鑰匙,t2 線程還在阻塞狀態(tài)進不來,只有下次輪到 t1 自己再次獲得時間片時才 能開門進入

(4) 當 t1 執(zhí)行完 synchronized{} 塊內(nèi)的代碼,這時候才會從 obj 房間出來并解開門上的鎖,喚醒 t2 線程并把鑰匙給他。t2 線程這時才可以進入 obj 房間,鎖住了門拿上鑰匙,執(zhí)行它的 count-- 代碼;

在這里插入圖片描述

3. 如果同步塊內(nèi)的線程拋出異常會發(fā)生什么?

public class ExceptionDemo {
    private static int count = 1;
    // 創(chuàng)建鎖對象
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            synchronized (object){
                System.out.println("線程t1正在執(zhí)行");
                // 死循環(huán)
                while (count==1){
                }
            }
        },"t1");
        Thread t2 = new Thread(()->{
            synchronized (object) {
                System.out.println("線程t2正在執(zhí)行");
                count--;
            }
        },"t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

執(zhí)行結(jié)果:

在這里插入圖片描述

可以看出線程t1執(zhí)行的是死循環(huán),所以每次線程上下文切換,線程t2都被阻塞了,拿不到鎖,從而無法執(zhí)行。

假如我們在線程執(zhí)行過程中制造一個異常:

public class ExceptionDemo {
    private static int count = 1;
    // 創(chuàng)建鎖對象
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            synchronized (object){
                System.out.println("線程t1正在執(zhí)行");
                while (count==1){
                    // 死循環(huán)中制造異常
                    Integer.parseInt("a");
                }
            }
        },"t1");
        Thread t2 = new Thread(()->{
            synchronized (object) {
                System.out.println("線程t2正在執(zhí)行");
                count--;
            }
        },"t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

執(zhí)行結(jié)果:

在這里插入圖片描述

當持有鎖對象的線程在執(zhí)行同步代碼快中的代碼時,如果出現(xiàn)異常,會釋放鎖,從而線程t2就可以拿到鎖對象去執(zhí)行自己同步代碼塊中的代碼了。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!     

相關(guān)文章

  • Java自定義equals產(chǎn)生的問題分析

    Java自定義equals產(chǎn)生的問題分析

    這篇文章主要介紹了Java自定義equals時super.equals帶來的問題分析,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路
    2023-01-01
  • spring boot整合mybatis+mybatis-plus的示例代碼

    spring boot整合mybatis+mybatis-plus的示例代碼

    這篇文章主要介紹了spring boot整合mybatis+mybatis-plus的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java算法之冒泡排序?qū)嵗a

    Java算法之冒泡排序?qū)嵗a

    今天小編就為大家分享一篇關(guān)于Java算法之冒泡排序?qū)嵗a,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Spring boot中使用ElasticSearch的方法詳解

    Spring boot中使用ElasticSearch的方法詳解

    這篇文章主要給大家介紹了關(guān)于Spring boot中使用ElasticSearch的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-01-01
  • 淺談為什么重寫equals()就要重寫hashCode()

    淺談為什么重寫equals()就要重寫hashCode()

    困擾我很久的問題,一直不明白為什么重寫equals()方法的時候要重寫hashCode()方法,這次總算弄明白了,作此分享,感興趣的可以了解一下
    2021-10-10
  • ElasticSearch整合SpringBoot搭建配置

    ElasticSearch整合SpringBoot搭建配置

    這篇文章主要為大家介紹了ElasticSearch整合SpringBoot搭建配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • VScode 打造完美java開發(fā)環(huán)境最新教程

    VScode 打造完美java開發(fā)環(huán)境最新教程

    這篇文章主要介紹了VScode 打造完美java開發(fā)環(huán)境最新教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • 值得Java程序猿閱讀的書籍

    值得Java程序猿閱讀的書籍

    這篇文章主要推薦了一些值得Java程序猿閱讀的書籍,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Springboot集成任務(wù)調(diào)度實現(xiàn)過程

    Springboot集成任務(wù)調(diào)度實現(xiàn)過程

    這篇文章主要介紹了Springboot集成任務(wù)調(diào)度實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • java中的類型自動轉(zhuǎn)換機制解析

    java中的類型自動轉(zhuǎn)換機制解析

    這篇文章主要介紹了java中的類型自動轉(zhuǎn)換機制,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論