首页 > 代码库 > java多线程基本概述(四)——死锁

java多线程基本概述(四)——死锁

package mytask;

public class Task {
    public static void main(String[] args) {
        DeadThread thread = new DeadThread();
        Thread t1 = new Thread(thread);
        t1.setName("a");
        Thread t2 = new Thread(thread);
        t2.setName("b");
        t1.start();
        t2.start();
    }    
}

class DeadThread implements Runnable{
    private String o1= new String("o1");
    private String o2 = new String("o2");
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("a")){
            synchronized(o1){
                System.out.println("a thread  enter outer monitor o1....");
                try{
                    Thread.sleep(3000);
                    System.out.println("a waiting for o2 monitor...");
                    synchronized(o2){
                        System.out.println("a thread enter inner monitr o2");
                    }
                }catch(InterruptedException e){
                    e.printStackTrace();
                }                
            }
        }else{
            synchronized(o2){
                System.out.println("b thread  enter outer monitor o1....");
                try{
                    Thread.sleep(3000);
                    System.out.println("b waiting for o1 monitor...");
                    synchronized(o1){
                        System.out.println("b thread enter inner monitr o1");
                    }
                }catch(InterruptedException e){
                    e.printStackTrace();
                }                
            }
        }
    }
    
}

输出结果:

a thread  enter outer monitor o1....
b thread  enter outer monitor o1....
a waiting for o2 monitor...
b waiting for o1 monitor...

一致处于阻塞状态,可以通过jps命令查看信息得到

8064 Task
3832
3388 Jps

然后再执行 jstack -l 8064 

得到信息

Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.6-b01 mixed mode):

"DestroyJavaVM" prio=6 tid=0x000000000096c000 nid=0x494 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"b" prio=6 tid=0x0000000006d66800 nid=0x548 waiting for monitor entry [0x000000000772f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at mytask.DeadThread.run(Task.java:40)
        - waiting to lock <0x00000007c099b648> (a java.lang.String)
        - locked <0x00000007c099b668> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
        - None

"a" prio=6 tid=0x0000000006d66000 nid=0x1354 waiting for monitor entry [0x000000000762f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at mytask.DeadThread.run(Task.java:27)
        - waiting to lock <0x00000007c099b668> (a java.lang.String)
        - locked <0x00000007c099b648> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
        - None

"Low Memory Detector" daemon prio=6 tid=0x00000000025bf000 nid=0x1890 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" daemon prio=10 tid=0x00000000025b5800 nid=0x1bb8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" daemon prio=10 tid=0x00000000025ac800 nid=0x1ee8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Attach Listener" daemon prio=10 tid=0x00000000025ab800 nid=0x480 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" daemon prio=10 tid=0x00000000025a8800 nid=0xebc runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" daemon prio=8 tid=0x0000000002592000 nid=0x1dd0 in Object.wait() [0x0000000006d2f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000007c0961300> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
        - locked <0x00000007c0961300> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
        - None

"Reference Handler" daemon prio=10 tid=0x000000000258e800 nid=0x1560 in Object.wait() [0x0000000006c2f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000007c09611d8> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:485)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
        - locked <0x00000007c09611d8> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
        - None

"VM Thread" prio=10 tid=0x0000000002588000 nid=0x1d38 runnable

"GC task thread#0 (ParallelGC)" prio=6 tid=0x00000000024e1800 nid=0x1e40 runnable

"GC task thread#1 (ParallelGC)" prio=6 tid=0x00000000024e3000 nid=0x1854 runnable

"GC task thread#2 (ParallelGC)" prio=6 tid=0x00000000024e4800 nid=0x1e00 runnable

"GC task thread#3 (ParallelGC)" prio=6 tid=0x00000000024e6800 nid=0x970 runnable

"VM Periodic Task Thread" prio=10 tid=0x00000000025c2000 nid=0xf00 waiting on condition

JNI global references: 882


Found one Java-level deadlock:
=============================
"b":
  waiting to lock monitor 0x0000000002598548 (object 0x00000007c099b648, a java.lang.String),
  which is held by "a"
"a":
  waiting to lock monitor 0x0000000002595de8 (object 0x00000007c099b668, a java.lang.String),
  which is held by "b"

Java stack information for the threads listed above:
===================================================
"b":
        at mytask.DeadThread.run(Task.java:40)
        - waiting to lock <0x00000007c099b648> (a java.lang.String)
        - locked <0x00000007c099b668> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:662)
"a":
        at mytask.DeadThread.run(Task.java:27)
        - waiting to lock <0x00000007c099b668> (a java.lang.String)
        - locked <0x00000007c099b648> (a java.lang.String)
        at java.lang.Thread.run(Thread.java:662)

Found 1 deadlock.

死锁的一个经典场景为哲学家就餐问题。 产生死锁的原因主要是:

(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态
的情况下占用资源。因此,对资源的分配要给予合理的规划。

java多线程基本概述(四)——死锁