John Jiang

          a cup of Java, cheers!
          https://github.com/johnshajiang/blog

             :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          Java并發基礎實踐--死鎖
          本文是Java并發基礎實踐系列中的一篇,介紹了最簡單的死鎖場景,并使用jstack產生的thread dump來查找死鎖。(2013.12.29最后更新)

          1. 死鎖
          為了能夠維護線程的安全性,Java提供的鎖機制,但不恰當地使用鎖則可能產生死鎖。死鎖是并發編程中一個無法繞開的問題。只要在一個任務中使用了一個以上的鎖,那么就存在死鎖的風險。
          死鎖產生的直接原因非常簡單,即兩個線程在相互等待對方所執有的鎖。

          2. 鎖順序死鎖
          在死鎖場景中,最典型的就是鎖順序死鎖,代碼清單1就是一個很常見的示例。
          清單1
          public class DeadLock {

              
          private Object leftLock = new Object();
              
          private Object rightLock = new Object();

              
          public void leftRight() {
                  
          synchronized (leftLock) {
                      
          try {
                          TimeUnit.SECONDS.sleep(
          3);
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }

                      
          synchronized (rightLock) {
                          System.out.println(
          "leftRight");
                      }
                  }
              }

              
          public void rightLeft() {
                  
          synchronized (rightLock) {
                      
          try {
                          TimeUnit.SECONDS.sleep(
          3);
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }

                      
          synchronized (leftLock) {
                          System.out.println(
          "leftRight");
                      }
                  }
              }

              
          public static void main(String[] args) {
                  
          final DeadLock deadLock = new DeadLock();

                  Thread t1 
          = new Thread(new Runnable() {

                      @Override
                      
          public void run() {
                          deadLock.leftRight();
                      }
                  });

                  Thread t2 
          = new Thread(new Runnable() {

                      @Override
                      
          public void run() {
                          deadLock.rightLeft();
                      }
                  });

                  t1.start();
                  t2.start();
              }
          }

          3. Thread Dump
          JDK提供了一組命令行工具,其中就包括jstack。通過jstack可以獲取當前正運行的Java進程的java stack和native stack信息。如果Java進程崩潰了,也可以通過它來獲取core file中的java stack和native stack信息,以方便我們定位問題。
          為了能夠使用jstack去輸出目標Java進程的thread dump,首先必須要弄清楚在執行清單1的程序時,該程序的進程號。JDK提供的另一個命令行工具jps可以獲取系統中所有Java進程的相關信息。
          在命令行窗口中執行命令jps,即可以得到清單2所示的結果
          清單2
          C:\Documents and Settings\Administrator>jps
          2848
          4552 DeadLock
          5256 Jps
          其中4552就是在筆者機器上執行程序DeadLock時所生成Java進程的進程號。
          然后再執行命令jstack 4552,在筆者的機器上就會得到清單3所示的結果
          清單3
          C:\Documents and Settings\Administrator>jstack 
          4552
          2013-12-29 18:45:41
          Full thread dump Java HotSpot(TM) Client VM (
          23.25-b01 mixed mode, sharing):

          "DestroyJavaVM" prio=6 tid=0x00878800 nid=0xd00 waiting on condition [0x00000000]
             java.lang.Thread.State: RUNNABLE

          "Thread-1" prio=6 tid=0x02b56c00 nid=0x14ec waiting for monitor entry [0x02fdf000]
             java.lang.Thread.State: BLOCKED (on object monitor)
                  at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
          33)
                  - waiting to lock <0x22be6598> (a java.lang.Object)
                  - locked <0x22be65a0> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          2.run(DeadLock.java:53)
                  at java.lang.Thread.run(Thread.java:
          724)

          "Thread-0" prio=6 tid=0x02b55c00 nid=0x354 waiting for monitor entry [0x02f8f000]
             java.lang.Thread.State: BLOCKED (on object monitor)
                  at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
          19)
                  - waiting to lock <0x22be65a0> (a java.lang.Object)
                  - locked <0x22be6598> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          1.run(DeadLock.java:45)
                  at java.lang.Thread.run(Thread.java:
          724)

          "Service Thread" daemon prio=6 tid=0x02b34800 nid=0x133c runnable [0x00000000]
             java.lang.Thread.State: RUNNABLE

          "C1 CompilerThread0" daemon prio=10 tid=0x02b13800 nid=0x10fc waiting on condition [0x00000000]
             java.lang.Thread.State: RUNNABLE

          "Attach Listener" daemon prio=10 tid=0x02b11c00 nid=0x1424 waiting on condition [0x00000000]
             java.lang.Thread.State: RUNNABLE

          "Signal Dispatcher" daemon prio=10 tid=0x02b10800 nid=0x1100 runnable [0x00000000]
             java.lang.Thread.State: RUNNABLE

          "Finalizer" daemon prio=8 tid=0x02af4c00 nid=0x1238 in Object.wait() [0x02daf000]
             java.lang.Thread.State: WAITING (on object monitor)
                  at java.lang.Object.wait(Native Method)
                  - waiting on <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
                  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
          135)
                  - locked <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
                  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
          151)
                  at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:
          189)

          "Reference Handler" daemon prio=10 tid=0x02af0000 nid=0x12e8 in Object.wait() [0x02d5f000]
             java.lang.Thread.State: WAITING (on object monitor)
                  at java.lang.Object.wait(Native Method)
                  - waiting on <0x22b60da0> (a java.lang.ref.Reference$Lock)
                  at java.lang.Object.wait(Object.java:
          503)
                  at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:
          133)
                  - locked <0x22b60da0> (a java.lang.ref.Reference$Lock)

          "VM Thread" prio=10 tid=0x02aee400 nid=0x129c runnable

          "VM Periodic Task Thread" prio=10 tid=0x02b48000 nid=0x89c waiting on condition

          JNI global references: 
          117


          Found one Java-level deadlock:
          =============================
          "Thread-1":
            waiting to lock monitor 0x02af4a3c (object 0x22be6598
          , a java.lang.Object),
            which is held by 
          "Thread-0"
          "Thread-0":
            waiting to lock monitor 0x02af310c (object 0x22be65a0
          , a java.lang.Object),
            which is held by 
          "Thread-1"

          Java stack information for the threads listed above:
          ===================================================
          "Thread-1":
                  at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
          33)
                  - waiting to lock <0x22be6598> (a java.lang.Object)
                  - locked <0x22be65a0> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          2.run(DeadLock.java:53)
                  at java.lang.Thread.run(Thread.java:
          724)
          "Thread-0":
                  at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
          19)
                  - waiting to lock <0x22be65a0> (a java.lang.Object)
                  - locked <0x22be6598> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          1.run(DeadLock.java:45)
                  at java.lang.Thread.run(Thread.java:
          724)

          Found 
          1 deadlock.
          在上述輸出中,我們可以很明確地看到一個死鎖
          "Thread-1":
            waiting to lock monitor 0x02af4a3c (object 0x22be6598
          , a java.lang.Object),
            which is held by 
          "Thread-0"
          "Thread-0":
            waiting to lock monitor 0x02af310c (object 0x22be65a0
          , a java.lang.Object),
            which is held by 
          "Thread-1"
          并且它還標明了程序是在哪個地方時發現了上述死鎖
          "Thread-1":
                  at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
          33)
                  - waiting to lock <0x22be6598> (a java.lang.Object)
                  - locked <0x22be65a0> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          2.run(DeadLock.java:53)
                  at java.lang.Thread.run(Thread.java:
          724)
          "Thread-0":
                  at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
          19)
                  - waiting to lock <0x22be65a0> (a java.lang.Object)
                  - locked <0x22be6598> (a java.lang.Object)
                  at concurrency.deadlock.DeadLock$
          1.run(DeadLock.java:45)
                  at java.lang.Thread.run(Thread.java:
          724)

          4. 小結
          死鎖產生的直接原因非常簡單,即兩個線程在相互等待對方所執有的鎖。鎖順序死鎖是其中最經典的場景,此外還有動態的鎖順序死鎖。雖然表現形式有所不同,但本質上都是兩個線程在以不同的順序來獲取相同鎖時,發生了死鎖問題。
          使用thread dump可以幫助我們分析死鎖產生的原因。除了直接使用jstack命令來獲取thread dump輸出以外,JDK還提供了jvisualvm工具,它能以可視化的方式展示Java程序的進程號并導出thread dump。
          posted on 2013-12-29 20:19 John Jiang 閱讀(12284) 評論(1)  編輯  收藏 所屬分類: JavaSEJavaConcurrency原創Java并發基礎實踐

          評論

          # re: Java并發基礎實踐--死鎖(原) 2014-01-01 12:17 私人訂制
          好東西學習了  回復  更多評論
            

          主站蜘蛛池模板: 库车县| 四川省| 饶河县| 偃师市| 得荣县| 克什克腾旗| 庆安县| 西和县| 墨江| 张家港市| 博罗县| 桂阳县| 成都市| 连平县| 施甸县| 梓潼县| 宜宾县| 洪湖市| 东阿县| 莱芜市| 南昌市| 阳信县| 区。| 澄江县| 商河县| 海淀区| 凤冈县| 涡阳县| 静海县| 格尔木市| 新乡市| 泾川县| 淮滨县| 周至县| 嘉祥县| 阿克陶县| 鄂托克旗| 宜黄县| 伊川县| 平湖市| 吉安市|