日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发:隐藏线程死锁

發(fā)布時(shí)間:2023/12/3 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发:隐藏线程死锁 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

大多數(shù)Java程序員熟悉Java線程死鎖概念。 它本質(zhì)上涉及2個(gè)線程,它們彼此永遠(yuǎn)等待。 這種情況通常是平面(同步)或ReentrantLock(讀或?qū)?#xff09;鎖排序問題的結(jié)果。

Found one Java-level deadlock: ============================= "pool-1-thread-2":waiting to lock monitor 0x0237ada4 (object 0x272200e8, a java.lang.Object),which is held by "pool-1-thread-1" "pool-1-thread-1":waiting to lock monitor 0x0237aa64 (object 0x272200f0, a java.lang.Object),which is held by "pool-1-thread-2"

好消息是,HotSpot JVM始終可以為您檢測(cè)到這種情況……還是嗎? 最近一個(gè)影響Oracle Service Bus生產(chǎn)環(huán)境的線程死鎖問題迫使我們重新審視此經(jīng)典問題并確定是否存在“隱藏”死鎖情況。 本文將通過一個(gè)簡(jiǎn)單的Java程序演示并復(fù)制非常特殊的鎖排序死鎖條件,最新的HotSpot JVM 1.7并未檢測(cè)到該情況。 您還可以在本文結(jié)尾處找到一個(gè)視頻 ,向您介紹Java示例程序和所使用的故障排除方法。

犯罪現(xiàn)場(chǎng)

我通常喜歡將主要的Java并發(fā)問題與犯罪現(xiàn)場(chǎng)進(jìn)行比較,在犯罪現(xiàn)場(chǎng)您扮演首席調(diào)查員的角色。 在這種情況下,“犯罪”是客戶IT環(huán)境的實(shí)際生產(chǎn)中斷。 您的工作是:

  • 收集所有證據(jù),提示和事實(shí)(線程轉(zhuǎn)儲(chǔ),日志,業(yè)務(wù)影響,負(fù)載數(shù)字…)
  • 詢問證人和領(lǐng)域?qū)<?#xff08;支持團(tuán)隊(duì),交付團(tuán)隊(duì),供應(yīng)商,客戶……)

調(diào)查的下一步是分析收集的信息,并建立一個(gè)或多個(gè)“可疑”的潛在清單以及清晰的證據(jù)。 最終,您希望將其范圍縮小到主要可疑或根本原因。 顯然,“直到證明有罪之前無罪”的法律在這里并不適用,恰恰相反。 缺乏證據(jù)可能會(huì)阻止您實(shí)現(xiàn)上述目標(biāo)。 接下來,您將看到Hotspot JVM缺少死鎖檢測(cè)并沒有必要證明您沒有在處理此問題。

犯罪嫌疑人

在此故障排除上下文中,“可疑”定義為具有以下有問題的執(zhí)行模式的應(yīng)用程序或中間件代碼。

  • 使用FLAT鎖,然后使用ReentrantLock WRITE鎖(執(zhí)行路徑#1)
  • 使用ReentrantLock READ鎖,然后使用FLAT鎖(執(zhí)行路徑#2)
  • 由2個(gè)Java線程并發(fā)執(zhí)行,但執(zhí)行順序相反

上面的鎖排序死鎖標(biāo)準(zhǔn)可以如下所示:

現(xiàn)在,讓我們通過示例Java程序來復(fù)制此問題,并查看JVM線程轉(zhuǎn)儲(chǔ)輸出。

示例Java程序

上面的死鎖條件是首先從我們的Oracle OSB問題案例中發(fā)現(xiàn)的。 然后,我們通過一個(gè)簡(jiǎn)單的Java程序重新創(chuàng)建了它。 您可以在此處 下載我們程序的完整源代碼。 該程序只是創(chuàng)建并觸發(fā)2個(gè)工作線程。 它們每個(gè)執(zhí)行不同的執(zhí)行路徑,并嘗試以不同的順序獲取共享對(duì)象上的鎖。 我們還創(chuàng)建了一個(gè)死鎖檢測(cè)器線程以進(jìn)行監(jiān)視和記錄。 現(xiàn)在,在下面找到實(shí)現(xiàn)2條不同執(zhí)行路徑的Java類。

package org.ph.javaee.training8;import java.util.concurrent.locks.ReentrantReadWriteLock;/*** A simple thread task representation* @author Pierre-Hugues Charbonneau**/ public class Task {// Object used for FLAT lockprivate final Object sharedObject = new Object();// ReentrantReadWriteLock used for WRITE & READ locksprivate final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();/*** Execution pattern #1*/public void executeTask1() {// 1. Attempt to acquire a ReentrantReadWriteLock READ locklock.readLock().lock();// Wait 2 seconds to simulate some work...try { Thread.sleep(2000);}catch (Throwable any) {}try { // 2. Attempt to acquire a Flat lock...synchronized (sharedObject) {}}// Remove the READ lockfinally {lock.readLock().unlock();} System.out.println("executeTask1() :: Work Done!");}/*** Execution pattern #2*/public void executeTask2() {// 1. Attempt to acquire a Flat locksynchronized (sharedObject) { // Wait 2 seconds to simulate some work...try { Thread.sleep(2000);}catch (Throwable any) {}// 2. Attempt to acquire a WRITE lock lock.writeLock().lock();try {// Do nothing}// Remove the WRITE lockfinally {lock.writeLock().unlock();}}System.out.println("executeTask2() :: Work Done!");}public ReentrantReadWriteLock getReentrantReadWriteLock() {return lock;} }

一旦觸發(fā)死鎖情況,就會(huì)使用JVisualVM生成JVM線程轉(zhuǎn)儲(chǔ)。

從Java線程轉(zhuǎn)儲(chǔ)示例中可以看到。 JVM未檢測(cè)到此死鎖條件(例如,不存在“發(fā)現(xiàn)一個(gè)Java級(jí)死鎖”),但很明顯,這兩個(gè)線程處于死鎖狀態(tài)。

根本原因:ReetrantLock READ鎖定行為

至此,我們發(fā)現(xiàn)的主要解釋與ReetrantLock READ鎖的用法有關(guān)。 讀鎖通常不設(shè)計(jì)為具有所有權(quán)概念。 由于沒有哪個(gè)線程持有讀取鎖的記錄,因此這似乎可以防止HotSpot JVM死鎖檢測(cè)器邏輯檢測(cè)到涉及讀鎖的死鎖。 從那時(shí)起,我們進(jìn)行了一些改進(jìn),但是我們可以看到JVM仍然無法檢測(cè)到這種特殊的死鎖情況。 現(xiàn)在,如果我們用寫鎖替換程序中的讀鎖(執(zhí)行模式2),那么JVM將最終檢測(cè)到死鎖情況,但是為什么呢?

Found one Java-level deadlock: ============================= "pool-1-thread-2":waiting for ownable synchronizer 0x272239c0, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),which is held by "pool-1-thread-1" "pool-1-thread-1":waiting to lock monitor 0x025cad3c (object 0x272236d0, a java.lang.Object),which is held by "pool-1-thread-2"Java stack information for the threads listed above: =================================================== "pool-1-thread-2":at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x272239c0> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer. parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)at java.util.concurrent.locks.AbstractQueuedSynchronizer. acquireQueued(AbstractQueuedSynchronizer.java:867)at java.util.concurrent.locks.AbstractQueuedSynchronizer. acquire(AbstractQueuedSynchronizer.java:1197)at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:945)at org.ph.javaee.training8.Task.executeTask2(Task.java:54)- locked <0x272236d0> (a java.lang.Object)at org.ph.javaee.training8.WorkerThread2.run(WorkerThread2.java:29)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)at java.lang.Thread.run(Thread.java:722) "pool-1-thread-1":at org.ph.javaee.training8.Task.executeTask1(Task.java:31)- waiting to lock <0x272236d0> (a java.lang.Object)at org.ph.javaee.training8.WorkerThread1.run(WorkerThread1.java:29)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)at java.lang.Thread.run(Thread.java:722)

這是因?yàn)轭愃朴谄矫骀i,JVM跟蹤寫入鎖。 這意味著HotSpot JVM死鎖檢測(cè)器似乎當(dāng)前被設(shè)計(jì)用來檢測(cè):

  • 對(duì)象監(jiān)視器上涉及FLAT鎖的死鎖
  • 死鎖涉及與WRITE鎖相關(guān)聯(lián)的已鎖定擁有的同步器

缺少讀取鎖每線程跟蹤似乎可以防止這種情況下的死鎖檢測(cè),并大大增加了故障排除的復(fù)雜性。 我建議您閱讀Doug Lea在整個(gè)問題上的評(píng)論 ,因?yàn)樵缭?005年就開始擔(dān)心由于某些潛在的鎖定開銷而可能添加每線程讀取保持跟蹤。 如果您懷疑涉及讀取鎖的隱藏死鎖情況,請(qǐng)?jiān)谙旅娴墓收吓懦ㄗh中查找:

  • 仔細(xì)分析線程調(diào)用堆棧跟蹤,它可能會(huì)揭示某些代碼潛在地獲取讀鎖,并阻止其他線程獲取寫鎖。
  • 如果您是代碼的所有者,請(qǐng)通過使用lock.getReadLockCount()方法來跟蹤讀取鎖的計(jì)數(shù)。

我期待著您的反饋,特別是對(duì)于具有此類涉及讀鎖的死鎖經(jīng)驗(yàn)的個(gè)人。 最后,在下面的視頻中找到通過示例Java程序的執(zhí)行和監(jiān)視來解釋這些發(fā)現(xiàn)的視頻。


參考: Java并發(fā)性: Java EE支持模式和Java教程博客中,我們的JCG合作伙伴 Pierre-Hugues Charbonneau 隱藏的線程死鎖 。

翻譯自: https://www.javacodegeeks.com/2013/02/java-concurrency-the-hidden-thread-deadlocks.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的Java并发:隐藏线程死锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。