欧美日韩不卡一区二区三区,www.蜜臀.com,高清国产一区二区三区四区五区,欧美日韩三级视频,欧美性综合,精品国产91久久久久久,99a精品视频在线观看

java語言

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

時(shí)間:2025-04-16 03:59:21 java語言 我要投稿
  • 相關(guān)推薦

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

  死鎖,是指兩個(gè)或多個(gè)動(dòng)作一直在等待其他動(dòng)作完成而使得所有動(dòng)作都始終處在阻塞的狀態(tài)。如何通過編程發(fā)現(xiàn)Java死鎖?下面就一起來了解看看吧!

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

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

  Java 5引入了ThreadMXBean接口,它提供了多種監(jiān)視線程的方法。我建議您了解所有這些方法,因?yàn)楫?dāng)您沒使用外部工具時(shí),它們會(huì)為您提供很多有用的操作以便您監(jiān)測(cè)程序性能。這里,我們感興趣的方法是findMonitorDeadlockedThreads,如過您使用的是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)度的方法是通過執(zhí)行器框架,即一組良好抽象并易于使用的多線程類。

  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

  this.scheduler.scheduleAtFixedRate(deadlockCheck, period, period, unit);

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

  void handleDeadlock(final ThreadInfo[] deadlockedThreads);

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

  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用來向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<Thread, StackTraceElement[]> 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());

  }

  }

  }

  }

  }

  }

  }

  }

  這一過程在所有的堆棧追蹤中反復(fù)進(jìn)行并為每個(gè)線程信息打印對(duì)應(yīng)的堆棧蹤跡。通過這種方式,我們可以準(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ì)返回沒有此類線程。為了避免可能出現(xiàn)的NullPointerException,我們需要警惕這種情況。最后,讓我們促成一個(gè)死鎖來看看系統(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è)的開銷可能會(huì)很大,你需要用你的程序來測(cè)試一下你是否真的需要死鎖檢測(cè)以及多久檢測(cè)一次。我建議死鎖檢測(cè)的時(shí)間間隔至少為幾分鐘,因?yàn)楦宇l繁的檢測(cè)并沒有太大的意義,原因是我們并沒有一個(gè)復(fù)原計(jì)劃,我們能做的只是調(diào)試和處理錯(cuò)誤或者重啟程序并祈禱不會(huì)再次發(fā)生死鎖。


【如何通過編程發(fā)現(xiàn)Java死鎖】相關(guān)文章:

如何學(xué)好Java語言編程08-03

java如何通過url讀取文件05-07

Java程序死鎖問題原理及解決方案10-04

java編程術(shù)語11-10

java編程基礎(chǔ)07-26

Java編程語言10-02

java教程之Java編程基礎(chǔ)09-12

Java如何通過Socket實(shí)現(xiàn)TCP服務(wù)端10-08

Java編程環(huán)境的搭建06-03