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) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态
的情况下占用资源。因此,对资源的分配要给予合理的规划。