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

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

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

服務器之家 - 編程語言 - Java教程 - java并發之synchronized

java并發之synchronized

2022-02-25 00:41onlythinking Java教程

這篇文章主要介紹了java并發關鍵字synchronized,包括內容synchronized的使用、synchronized背后的Monitor、synchronized保證可見性和防重排序、使用synchronized注意嵌套鎖定,具體內容請看下面文章吧

前言:

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

本章節探索Java關鍵字synchronized。主要包含以下幾個內容。

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

 

1、使用方式

synchronized 關鍵字有以下四種使用方式:

  • 實例方法
  • 靜態方法
  • 實例方法中的代碼塊
  • 靜態方法中的代碼塊

實例方法同步和實例方法代碼塊同步:

// 實例方法同步和實例方法代碼塊同步
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;
  }
}


靜態方法同步和靜態方法代碼塊同步:

// 靜態方法同步和靜態方法代碼塊同步
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;
  }
}

使用關鍵字synchronized實現同步是在JVM內部實現處理,對于應用開發人員來說它是隱式進行的。

每個Java對象都有一個與之關聯的monitor。

當線程調用實例同步方法時,會自動獲取實例對象的monitor。

當線程調用靜態同步方法時,會自動獲取該類Class實例對象的monitor。

Class實例:JVM為每個加載的class創建了對應的Class實例來保存class及interface的所有信息;

 

2、Monitor(管程)

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

如下圖,線程通過入口隊列(Entry Queue)到達訪問共享數據,若有線程占用轉移等待隊列(Wait Queue),線程訪問共享數據完后觸發通知或轉移到信號隊列(Signal Queue)。

java并發之synchronized

2.1 關于管程模型

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

為什么會有這三種模型?

假設有兩個線程A和B,線程B先進入monitor執行,線程A處于等待。當線程A執行完準備退出的時候,是先退出monitor還是先喚醒線程A?這時就出現了Mesa語義, Hoare語義和Brinch Hansen語義 三種不同版本的處理方式。

2.2 Mesa Semantics

Mesa模型中 線程只會出現在WaitQueue,EntryQueue,Monitor。

當線程B發出信號告知線程A時,線程A從WaitQueue 轉移到EntryQueue并等待線程B退出Monitor之后再進入Monitor。也就是先通知再退出。

java并發之synchronized

2.3 Brinch Hanson Semantics

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

java并發之synchronized

2.4 Hoare Semantics

Hoare模型中 線程會分別出現在WaitQueue,EntryQueue,SignalQueue,Monitor中。

當線程B發出信號告知線程A并且退出Monitor轉移到SignalQueue,線程A進入Monitor。當線程A離開Monitor后,線程B再次回到Monitor。

java并發之synchronized

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

我們看到兩個關鍵指令 monitorenter 和 monitorexit

java并發之synchronized

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 ……

每個對象都有一個關聯monitor。

線程執行 monitorenter 時嘗試獲取關聯對象的monitor。

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

如果獲取成功則monitor計數器設置為1并將當前線程設為monitor擁有者,如果線程再次進入計數器自增,以表示進入次數。

2.6 monitorexit

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

線程執行monitorexit 時,monitor計數器自減,當計數器變為0時釋放對象monitor。

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

 

3、可見性和重排序

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

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

另外Java編譯器和Java虛擬機為了達到優化性能的目的會對代碼中的指令進行重排序。但是重排序會導致多線程執行出現意想不到的錯誤。使用synchronized關鍵字可以消除對同步塊共享變量的重排序。

 

4、局限與性能

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

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

關于性能問題。進入和退出同步塊操作性能開銷很小,但是過大范圍設置同步或者在頻繁的循環中使用同步可能會導致性能問題。

可重入,在monitorenter指令解讀中,可以看出synchronized是可重入,重入一般發生在同步方法嵌套調用中。不過要防止嵌套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) {
      }
  }
}

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

  • 線程A調用lock() ,進入鎖定代碼執行。
  • 線程B調用lock() ,得到monitorObj的monitor后等待線程B喚醒。
  • 線程A執行完鎖定代碼后,調用unlock() ,在嘗試獲取monitorObj的monitor時,發現有線程占用,也一直掛起。
  • 這樣線程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();
          }
      }
  }
}

總結:

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

原文鏈接:https://www.onlythinking.com/2020/06/18/java%E5%B9%B6%E5%8F%91%E4%B9%8Bsynchronized/

延伸 · 閱讀

精彩推薦
  • Java教程Java并發編程之阻塞隊列(BlockingQueue)詳解

    Java并發編程之阻塞隊列(BlockingQueue)詳解

    這篇文章主要介紹了詳解Java阻塞隊列(BlockingQueue)的實現原理,阻塞隊列是Java util.concurrent包下重要的數據結構,有興趣的可以了解一下...

    小黑說Java9532021-12-27
  • Java教程解決Java J2EE亂碼問題的方法

    解決Java J2EE亂碼問題的方法

    這篇文章主要為大家詳細介紹了解決Java J2EE亂碼問題的方法的相關資料,需要的朋友可以參考下 ...

    游趣吧5312020-04-18
  • Java教程學習Java對網絡安全的重要性

    學習Java對網絡安全的重要性

    作為新一代威脅的出現,Java已經成為包括網絡安全在內的應用程序最常用的編程語言之一。如果你從事應用程序開發,你將知道Java在日常使用中無處不在...

    粵嵌教育7592021-12-28
  • Java教程Java日常練習題,每天進步一點點(6)

    Java日常練習題,每天進步一點點(6)

    下面小編就為大家帶來一篇Java基礎的幾道練習題(分享)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以...

    牛哄哄的柯南10832021-10-19
  • Java教程Maven配置文件pom.xml詳解

    Maven配置文件pom.xml詳解

    什么是POM?這篇文章主要介紹了Maven的配置文件pom.xml,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Yakov7072020-11-25
  • Java教程怎樣使用PowerMockito 測試靜態方法

    怎樣使用PowerMockito 測試靜態方法

    這篇文章主要介紹了使用PowerMockito 測試靜態的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教...

    林大蟲子3882021-10-06
  • Java教程Java優先隊列(PriorityQueue)重寫compare操作

    Java優先隊列(PriorityQueue)重寫compare操作

    這篇文章主要介紹了Java優先隊列(PriorityQueue)重寫compare操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    微觀盡頭3552020-10-08
  • Java教程Java關于List集合去重方案詳細介紹

    Java關于List集合去重方案詳細介紹

    實際項目開發中,很多業務場景下都會遇見集合去重。在說到List集合去重之前,首先我們回顧下普通類型的list如何去重...

    JavaEdge.11432022-01-04
主站蜘蛛池模板: 天天综合天天综合 | 日本高清视频网站 | 国产精品亚洲w码日韩中文 国产精品香蕉在线观看不卡 | 亚洲va天堂va国产va久久 | 欧美老肥妇bbbw | 久久99精国产一区二区三区四区 | 亚洲国产欧美在线人网站 | 精品操 | 韩国三级在线 | 国产高清在线精品一区二区 | 日本人啪啪 | 污丝瓜视频 | 日本道在线播放 | 韩国激情网 | 臀精插宫NP文| 贰佰麻豆剧果冻传媒一二三区 | 亚洲国产综合久久久无码色伦 | 秋霞一级黄色片 | 成年人免费在线看 | 忘忧草在线社区WWW日本-韩国 | 欧美大屁屁 | 91久久夜色精品国产九色 | 无码区国产区在线播放 | 色婷婷久久综合中文久久一本` | 四虎影院在线免费观看视频 | 亚洲精品一二区 | 热久久亚洲| 亚洲国产日韩欧美一区二区三区 | 欧美精品v日韩精品v国产精品 | 91免费精品国自产拍在线可以看 | 婷婷色天使在线视频观看 | 国产欧美一区二区三区免费 | 久久国产视频网 | 91综合精品网站久久 | 精品无码国产AV一区二区三区 | 国产成人一区二区三区视频免费蜜 | 成年男女免费视频观看性 | 亚洲欧洲日产国码无码av | 男人看的网址 | 精品在线小视频 | 4438成人网 |