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

java并發(fā)之synchronized

 更新時(shí)間:2021年10月22日 09:40:04   作者:onlythinking  
這篇文章主要介紹了java并發(fā)關(guān)鍵字synchronized,包括內(nèi)容synchronized的使用、synchronized背后的Monitor、synchronized保證可見性和防重排序、使用synchronized注意嵌套鎖定,具體內(nèi)容請看下面文章吧

前言:

Java為我們提供了隱式(synchronized聲明方式)和顯式(java.util.concurrentAPI編程方式)兩種工具來避免線程爭用。

本章節(jié)探索Java關(guān)鍵字synchronized。主要包含以下幾個(gè)內(nèi)容。

  • synchronized關(guān)鍵字的使用;
  • synchronized背后的Monitor(管程);
  • synchronized保證可見性和防重排序;
  • 使用synchronized注意嵌套鎖定。

1、使用方式

synchronized 關(guān)鍵字有以下四種使用方式:

  • 實(shí)例方法
  • 靜態(tài)方法
  • 實(shí)例方法中的代碼塊
  • 靜態(tài)方法中的代碼塊

實(shí)例方法同步和實(shí)例方法代碼塊同步:

// 實(shí)例方法同步和實(shí)例方法代碼塊同步
public class SynchronizedTest {
    private int count;
    public void setCountPart(int num) {
        synchronized (this) {
            this.count += num;
        }
    }
    public synchronized void setCount(int num) {
        this.count += num;
    }
}


靜態(tài)方法同步和靜態(tài)方法代碼塊同步:

// 靜態(tài)方法同步和靜態(tài)方法代碼塊同步
public class SynchronizedTest {
    private static int count;
    public static void setCountPart(int num) {
        synchronized (SynchronizedTest.class) {
            count += num;
        }
    }
    public static synchronized void setCount(int num) {
        count += num;
    }
}

使用關(guān)鍵字synchronized實(shí)現(xiàn)同步是在JVM內(nèi)部實(shí)現(xiàn)處理,對于應(yīng)用開發(fā)人員來說它是隱式進(jìn)行的。

每個(gè)Java對象都有一個(gè)與之關(guān)聯(lián)的monitor

當(dāng)線程調(diào)用實(shí)例同步方法時(shí),會自動獲取實(shí)例對象的monitor

當(dāng)線程調(diào)用靜態(tài)同步方法時(shí),會自動獲取該類Class實(shí)例對象的monitor。

Class實(shí)例:JVM為每個(gè)加載的class創(chuàng)建了對應(yīng)的Class實(shí)例來保存class及interface的所有信息;

2、Monitor(管程)

Monitor 直譯為監(jiān)視器,中文圈里稱為管程。它的作用是讓線程互斥,保護(hù)共享數(shù)據(jù),另外也可以向其它線程發(fā)送滿足條件的信號。

如下圖,線程通過入口隊(duì)列(Entry Queue)到達(dá)訪問共享數(shù)據(jù),若有線程占用轉(zhuǎn)移等待隊(duì)列(Wait Queue),線程訪問共享數(shù)據(jù)完后觸發(fā)通知或轉(zhuǎn)移到信號隊(duì)列(Signal Queue)。

2.1 關(guān)于管程模型

網(wǎng)上查詢很多文章,大多數(shù)羅列 “ Hasen 模型、Hoare 模型和 MESA模型 ”這些名詞,看過之后我還是一知半解。本著對知識的求真,查找溯源,找到了以下資料。

為什么會有這三種模型?

假設(shè)有兩個(gè)線程A和B,線程B先進(jìn)入monitor執(zhí)行,線程A處于等待。當(dāng)線程A執(zhí)行完準(zhǔn)備退出的時(shí)候,是先退出monitor還是先喚醒線程A?這時(shí)就出現(xiàn)了Mesa語義, Hoare語義和Brinch Hansen語義 三種不同版本的處理方式。

2.2 Mesa Semantics

Mesa模型中 線程只會出現(xiàn)在WaitQueue,EntryQueue,Monitor。

當(dāng)線程B發(fā)出信號告知線程A時(shí),線程A從WaitQueue 轉(zhuǎn)移到EntryQueue并等待線程B退出Monitor之后再進(jìn)入Monitor。也就是先通知再退出。

2.3 Brinch Hanson Semantics

Brinch Hanson模型和Mesa模型類似區(qū)別在于僅允許線程B退出Monitor后才能發(fā)送信號給線程A。也就是先退出再通知。

2.4 Hoare Semantics

Hoare模型中 線程會分別出現(xiàn)在WaitQueueEntryQueue,SignalQueueMonitor中。

當(dāng)線程B發(fā)出信號告知線程A并且退出Monitor轉(zhuǎn)移到SignalQueue,線程A進(jìn)入Monitor。當(dāng)線程A離開Monitor后,線程B再次回到Monitor。

https://www.andrew.cmu.edu/course/15-440-kesden/applications/ln/lecture6.html

https://cseweb.ucsd.edu/classes/sp17/cse120-a/applications/ln/lecture8.html

Java里面monitor是如何處理?

我們通過反編譯class文件看下Synchronized工作原理。

public class SynchronizedTest {
    private int count;
    public void setCountPart(int num) {
        synchronized (this) {
            this.count += num;
        }
    }
}

編譯和反編譯命令

javac SynchronizedTest.java
javap -v SynchronizedTest

我們看到兩個(gè)關(guān)鍵指令 monitorenter monitorexit

2.5 monitorenter

Each object has a monitor associated with it. The thread that executes monitorenter gains ownership of the monitor associated with objectref. If another thread already owns the monitor associated with objectref, the current thread ……

每個(gè)對象都有一個(gè)關(guān)聯(lián)monitor。

線程執(zhí)行 monitorenter 時(shí)嘗試獲取關(guān)聯(lián)對象的monitor。

獲取時(shí)如果對象的monitor被另一個(gè)線程占有,則等待對方釋放monitor后再次嘗試獲取。

如果獲取成功則monitor計(jì)數(shù)器設(shè)置為1并將當(dāng)前線程設(shè)為monitor擁有者,如果線程再次進(jìn)入計(jì)數(shù)器自增,以表示進(jìn)入次數(shù)。

2.6 monitorexit

The current thread should be the owner of the monitor associated with the instance referenced by objectref……

線程執(zhí)行monitorexit 時(shí),monitor計(jì)數(shù)器自減,當(dāng)計(jì)數(shù)器變?yōu)?時(shí)釋放對象monitor。

原文:https://docs.oracle.com/javase/specs/jvms/se6/html/Instructions2.doc9.html

3、可見性和重排序

在介紹Java并發(fā)內(nèi)存模型詳情的時(shí)候,我們提到過線程訪問共享對象時(shí)會先拷貝副本到CPU緩存,修改后返回CPU緩存,然后等待時(shí)機(jī)刷新到主存。這樣一來另外線程讀到的數(shù)據(jù)副本就不是最新,導(dǎo)致了數(shù)據(jù)的不一致,一般也將這種問題稱為線程可見性問題。

不過在使用synchronized關(guān)鍵字的時(shí)候,情況有所不同。線程在進(jìn)入synchronized后會同步該線程可見的所有變量,退出synchronized后,會將所有修改的變量直接同步到主存,可視為跳過了CPU緩存,這樣一來就避免了可見性問題。

另外Java編譯器和Java虛擬機(jī)為了達(dá)到優(yōu)化性能的目的會對代碼中的指令進(jìn)行重排序。但是重排序會導(dǎo)致多線程執(zhí)行出現(xiàn)意想不到的錯(cuò)誤。使用synchronized關(guān)鍵字可以消除對同步塊共享變量的重排序。

4、局限與性能

synchronized給我們提供了同步處理的便利,但是它在某些場景下也存在局限性,比如以下場景。

  • 讀多寫少場景。讀動作其實(shí)是安全,我們應(yīng)該嚴(yán)格控制寫操作。替代方案使用讀寫鎖readwritelock。如果只有一個(gè)線程進(jìn)行寫操作,可使用volatile關(guān)鍵字替代。
  • 允許多個(gè)線程同時(shí)進(jìn)入場景。synchronized限制了每次只有一個(gè)線程可進(jìn)入。替代方案使用信號量semaphore。
  • 需要保證搶占資源公平性。synchronized并不保證線程進(jìn)入的公平性。替代方案公平鎖FairLock

關(guān)于性能問題。進(jìn)入和退出同步塊操作性能開銷很小,但是過大范圍設(shè)置同步或者在頻繁的循環(huán)中使用同步可能會導(dǎo)致性能問題。

可重入,在monitorenter指令解讀中,可以看出synchronized是可重入,重入一般發(fā)生在同步方法嵌套調(diào)用中。不過要防止嵌套monitor死鎖問題。

比如下面代碼會直接造成死鎖:

private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1()   {
    synchronized (lock1) {
        synchronized (lock2) {
        }
    }
}
public void method2()   {
    synchronized (lock2) {
        synchronized (lock1) {
        }
    }
}

現(xiàn)實(shí)情況中,開發(fā)一般都不會出現(xiàn)以上代碼。但在使用 wait() notify() 很可能會出現(xiàn)阻塞鎖定。下面是一個(gè)模擬鎖的實(shí)現(xiàn)。

  • 線程A調(diào)用lock() ,進(jìn)入鎖定代碼執(zhí)行。
  • 線程B調(diào)用lock() ,得到monitorObjmonitor后等待線程B喚醒。
  • 線程A執(zhí)行完鎖定代碼后,調(diào)用unlock() ,在嘗試獲取monitorObjmonitor時(shí),發(fā)現(xiàn)有線程占用,也一直掛起。
  • 這樣線程A B 就互相干瞪眼!
public class Lock{
protected MonitorObj monitorObj = new MonitorObj();
    protected boolean isLocked = false;
    public void lock() throws InterruptedException{
        synchronized(this){
            while(isLocked){
                synchronized(this.monitorObj){
                    this.monitorObj.wait();
                }
            }
            isLocked = true;
        }
    }
    public void unlock(){
        synchronized(this){
            this.isLocked = false;
            synchronized(this.monitorObj){
                this.monitorObj.notify();
            }
        }
    }
}

總結(jié):

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

相關(guān)文章

  • 基于Java SSM的健康管理小程序的實(shí)現(xiàn)

    基于Java SSM的健康管理小程序的實(shí)現(xiàn)

    本篇文章主要為大家分享了基于SSM健康管理小程序的設(shè)計(jì)與實(shí)現(xiàn)。感興趣的小伙伴可以了解一下
    2021-11-11
  • Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    這篇文章主要介紹了Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 詳解Maven 搭建spring boot多模塊項(xiàng)目(附源碼)

    詳解Maven 搭建spring boot多模塊項(xiàng)目(附源碼)

    這篇文章主要介紹了詳解Maven 搭建spring boot多模塊項(xiàng)目(附源碼),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-09-09
  • RocketMQ的順序消費(fèi)機(jī)制詳解

    RocketMQ的順序消費(fèi)機(jī)制詳解

    這篇文章主要介紹了RocketMQ的順序消費(fèi)機(jī)制詳解,順序消息是指對于一個(gè)指定的?Topic?,消息嚴(yán)格按照先進(jìn)先出(FIFO)的原則進(jìn)行消息發(fā)布和消費(fèi),即先發(fā)布的消息先消費(fèi),后發(fā)布的消息后消費(fèi),,需要的朋友可以參考下
    2023-10-10
  • Java爬蟲范例之使用Htmlunit爬取學(xué)校教務(wù)網(wǎng)課程表信息

    Java爬蟲范例之使用Htmlunit爬取學(xué)校教務(wù)網(wǎng)課程表信息

    htmlunit 是一款開源的java 頁面分析工具,讀取頁面后,可以有效的使用htmlunit分析頁面上的內(nèi)容。項(xiàng)目可以模擬瀏覽器運(yùn)行,被譽(yù)為java瀏覽器的開源實(shí)現(xiàn)。今天我們用這款分析工具來爬取學(xué)校教務(wù)網(wǎng)課程表信息
    2021-11-11
  • Mybatis generator修改Mapper.java文件實(shí)現(xiàn)詳解

    Mybatis generator修改Mapper.java文件實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了Mybatis generator修改Mapper.java文件實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Java中自增和自減操作符(++/--)的那些事

    Java中自增和自減操作符(++/--)的那些事

    這篇文章主要給大家介紹了關(guān)于Java中自增和自減操作符(++/--)的那些事,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    這篇文章主要介紹了IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 詳解Spring MVC事務(wù)配置

    詳解Spring MVC事務(wù)配置

    這篇文章主要介紹了詳解Spring MVC事務(wù)配置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java常用對象操作工具代碼實(shí)例

    Java常用對象操作工具代碼實(shí)例

    這篇文章主要介紹了Java常用對象操作工具代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評論