如何通過(guò)編程發(fā)現(xiàn)Java死鎖

今天就跟大家聊聊有關(guān)如何通過(guò)編程發(fā)現(xiàn)Java死鎖,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)、曲沃網(wǎng)絡(luò)推廣、成都微信小程序、曲沃網(wǎng)絡(luò)營(yíng)銷、曲沃企業(yè)策劃、曲沃品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供曲沃建站搭建服務(wù),24小時(shí)服務(wù)熱線:18982081108,官方網(wǎng)址:muchs.cn

死鎖是指,兩個(gè)或多個(gè)動(dòng)作一直在等待其他動(dòng)作完成而使得所有動(dòng)作都始終處在阻塞的狀態(tài)。想要在開(kāi)發(fā)階段檢測(cè)到死鎖是非常困難的,而想要解除死鎖往往需要重新啟動(dòng)程序。更糟的是,死鎖通常發(fā)生在負(fù)載最重的生產(chǎn)過(guò)程中,而想要在測(cè)試中發(fā)現(xiàn)它,十分不易。之所以這么說(shuō),是因?yàn)闇y(cè)試線程之間所有可能的交叉是不現(xiàn)實(shí)的。盡管出現(xiàn)了一些靜態(tài)分析庫(kù)可以幫助我們發(fā)現(xiàn)可能出現(xiàn)的死鎖,我們還是有必要在運(yùn)行時(shí)檢測(cè)到死鎖,并且得到有用的信息,以便我們解決這個(gè)問(wèn)題或者重啟程序,或者做些其他的事情。

在編程中使用ThreadMXBean類來(lái)檢測(cè)死鎖

Java  5引入了ThreadMXBean接口,它提供了多種監(jiān)視線程的方法。我建議您了解所有這些方法,因?yàn)楫?dāng)您沒(méi)使用外部工具時(shí),它們會(huì)為您提供很多有用的操作以便您監(jiān)測(cè)程序性能。這里,我們感興趣的方法是findMonitorDeadlockedThreads,如過(guò)您使用的是Java  6,對(duì)應(yīng)的方法是findDeadlockedThreads。二者的區(qū)別的是,findDeadlockedThreads還可以檢測(cè)到owner  locks(java.util.concurrent)引起的死鎖,而findMonitorDeadlockedThreads只能檢測(cè)monitor  locks(例如,同步塊)。由于保留老版本的方法只是出于兼容性的考慮,所以我將使用新版本的方法。在這里,編程的思想是把對(duì)死鎖的周期性檢測(cè)封裝到一個(gè)可重用組件里,之后我們只需啟動(dòng)它、隨它去。

一種實(shí)現(xiàn)調(diào)度的方法是通過(guò)執(zhí)行器框架,即一組良好抽象并易于使用的多線程類。

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);  this.scheduler.scheduleAtFixedRate(deadlockCheck, period, period, unit);

就是那么簡(jiǎn)單,在我們通過(guò)選擇周期和時(shí)間單位而設(shè)置了一個(gè)特定時(shí)間后,就得到了一個(gè)周期性調(diào)用的線程。接著,我們想使功用得以拓展從而允許用戶提供在程序檢測(cè)到死鎖時(shí)所觸發(fā)的行為。***,我們需要一個(gè)方法來(lái)接收用于描述死鎖中所有線程的一系列對(duì)象。

void handleDeadlock(final ThreadInfo deadlockedThreads);

現(xiàn)在,實(shí)現(xiàn)死鎖檢測(cè)類已經(jīng)萬(wàn)事俱備了。

public interface DeadlockHandler { void handleDeadlock(final ThreadInfo  deadlockedThreads); } public class DeadlockDetector { private final  DeadlockHandler deadlockHandler; private final long period; private final  TimeUnit unit; private final ThreadMXBean mbean =  ManagementFactory.getThreadMXBean; private final ScheduledExecutorService  scheduler = Executors.newScheduledThreadPool(1); final Runnable deadlockCheck =  new Runnable { @Override public void run { long deadlockedThreadIds =  DeadlockDetector.this.mbean.findDeadlockedThreads; if (deadlockedThreadIds !=  null) { ThreadInfo threadInfos =  DeadlockDetector.this.mbean.getThreadInfo(deadlockedThreadIds);  DeadlockDetector.this.deadlockHandler.handleDeadlock(threadInfos); } } }; public  DeadlockDetector(final DeadlockHandler deadlockHandler, final long period, final  TimeUnit unit) { this.deadlockHandler = deadlockHandler; this.period = period;  this.unit = unit; } public void start { this.scheduler.scheduleAtFixedRate(  this.deadlockCheck, this.period, this.period, this.unit); } }

讓我們動(dòng)手試試。首先,我們要?jiǎng)?chuàng)建一個(gè)handler用來(lái)向System.err輸出死鎖線程的信息。在現(xiàn)實(shí)場(chǎng)景中,我們可以用它發(fā)送郵件,比如:

public class DeadlockConsoleHandler implements DeadlockHandler { @Override  public void handleDeadlock(final ThreadInfo deadlockedThreads) { if  (deadlockedThreads != null) { System.err.println("Deadlock detected!"); Map  stackTraceMap = Thread.getAllStackTraces; for (ThreadInfo threadInfo :  deadlockedThreads) { if (threadInfo != null) { for (Thread thread :  Thread.getAllStackTraces.keySet) { if (thread.getId == threadInfo.getThreadId) {  System.err.println(threadInfo.toString.trim); for (StackTraceElement ste :  thread.getStackTrace) { System.err.println("t" + ste.toString.trim); } } } } } }  } }

這一過(guò)程在所有的堆棧追蹤中反復(fù)進(jìn)行并為每個(gè)線程信息打印對(duì)應(yīng)的堆棧蹤跡。通過(guò)這種方式,我們可以準(zhǔn)確知道每個(gè)線程等待的位置和對(duì)象。但這個(gè)方法有一個(gè)缺陷——當(dāng)一個(gè)線程只是暫時(shí)等待時(shí),可能會(huì)被當(dāng)作一個(gè)暫時(shí)的死鎖,從而引發(fā)錯(cuò)誤的警報(bào)。出于此,當(dāng)我們處理死鎖時(shí),原始線程不能繼續(xù)存在而findDeadlockedThreads方法會(huì)返回沒(méi)有此類線程。為了避免可能出現(xiàn)的NullPointerException,我們需要警惕這種情況。***,讓我們促成一個(gè)死鎖來(lái)看看系統(tǒng)是如何運(yùn)行的。

DeadlockDetector deadlockDetector = new DeadlockDetector(new  DeadlockConsoleHandler, 5, TimeUnit.SECONDS); deadlockDetector.start; final  Object lock1 = new Object; final Object lock2 = new Object; Thread thread1 = new  Thread(new Runnable { @Override public void run {synchronized (lock1) {  System.out.println("Thread1 acquired lock1"); try {  TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException ignore) { }  synchronized (lock2) { System.out.println("Thread1 acquired lock2"); } } } });  thread1.start; Thread thread2 = new Thread(new Runnable { @Override public void  run { synchronized (lock2) { System.out.println("Thread2 acquired lock2");  synchronized (lock1) { System.out.println("Thread2 acquired lock1"); } } } });  thread2.start;

輸出:

Thread1 acquired lock1 Thread2 acquired lock2 Deadlock detected! “Thread-1”  Id=11 BLOCKED on java.lang.Object@68ab95e6 owned by “Thread-0” Id=10  deadlock.DeadlockTester$2.run(DeadlockTester.java:42)  java.lang.Thread.run(Thread.java:662) “Thread-0” Id=10 BLOCKED on  java.lang.Object@58fe64b9 owned by “Thread-1” Id=11  deadlock.DeadlockTester$1.run(DeadlockTester.java:28)  java.lang.Thread.run(Thread.java:662)

記住,死鎖檢測(cè)的開(kāi)銷可能會(huì)很大,你需要用你的程序來(lái)測(cè)試一下你是否真的需要死鎖檢測(cè)以及多久檢測(cè)一次。我建議死鎖檢測(cè)的時(shí)間間隔至少為幾分鐘,因?yàn)楦宇l繁的檢測(cè)并沒(méi)有太大的意義,原因是我們并沒(méi)有一個(gè)復(fù)原計(jì)劃,我們能做的只是調(diào)試和處理錯(cuò)誤或者重啟程序并祈禱不會(huì)再次發(fā)生死鎖。如果你有關(guān)于解決死鎖問(wèn)題的好建議或者關(guān)于這個(gè)解決方案的疑問(wèn),請(qǐng)?jiān)谙旅媪粞浴?/p>

看完上述內(nèi)容,你們對(duì)如何通過(guò)編程發(fā)現(xiàn)Java死鎖有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

網(wǎng)頁(yè)名稱:如何通過(guò)編程發(fā)現(xiàn)Java死鎖
網(wǎng)址分享:http://muchs.cn/article40/ihdoho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、域名注冊(cè)、面包屑導(dǎo)航、網(wǎng)站收錄、建站公司服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)