目录
Java避免死锁的几个常见方法
死锁产生的条件
上死锁代码
然后 :jstack 14320 >> jstack.text
Java避免死锁的几个常见方法
Java避免死锁的几个常见方法
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
死锁产生的条件
- 互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
- 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
- 不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
- 环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链死锁问题
上死锁代码
package cn.net.cdsz.ccb.test;
public class TestDeadLock {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable {
@Override
public void run() {
synchronized (obj1) {
System.out.println("Thread1 拿到 obj1 的锁");
try {
//停顿2秒的意义在于,让thread2线程拿到obj2的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("Thread1 拿到 obj2 的锁");
}
}
}
}
private static class Thread2 implements Runnable {
@Override
public void run() {
synchronized (obj2) {
System.out.println("Thread2 拿到 obj2 的锁");
try {
//停顿2秒的意义在于,让thread1线程拿到obj1的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("Thread2 拿到 obj1 的锁");
}
}
}
}
}
一直等待下了。。。
去找pid:14320
然后 :jstack 14320 >> jstack.text
得到以下内容:
2023-04-14 14:51:33
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.31-b07 mixed mode):
"JMX server connection timeout 21" #21 daemon prio=5 os_prio=0 tid=0x000000002167d800 nid=0x6108 in Object.wait() [0x00000000225ef000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x000000076e3b32b8> (a [I)
at java.lang.Thread.run(Thread.java:745)
"RMI Scheduler(0)" #20 daemon prio=5 os_prio=0 tid=0x0000000021674800 nid=0x3d78 waiting on condition [0x00000000224ee000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076dc34d08> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
"RMI TCP Connection(1)-192.168.136.113" #19 daemon prio=5 os_prio=0 tid=0x0000000021a3b800 nid=0x10c0 runnable [0x00000000223ee000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x000000076e281978> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:550)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(TCPTransport.java:683)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1/410101441.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
"RMI TCP Accept-0" #18 daemon prio=5 os_prio=0 tid=0x00000000212dc000 nid=0x8584 runnable [0x000000000153e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:404)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x000000076dc69d98> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)
at java.lang.Thread.run(Thread.java:745)
"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x000000000365b000 nid=0xae0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #15 prio=5 os_prio=0 tid=0x000000001ec17000 nid=0x69ac waiting for monitor entry [0x0000000020a1f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at cn.net.cdsz.ccb.test.TestDeadLock$Thread2.run(TestDeadLock.java:46)
- waiting to lock <0x000000076c88add0> (a java.lang.Object)
- locked <0x000000076c88ade0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0" #14 prio=5 os_prio=0 tid=0x000000001ec24800 nid=0x8d08 waiting for monitor entry [0x000000002091f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at cn.net.cdsz.ccb.test.TestDeadLock$Thread1.run(TestDeadLock.java:26)
- waiting to lock <0x000000076c88ade0> (a java.lang.Object)
- locked <0x000000076c88add0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Service Thread" #13 daemon prio=9 os_prio=0 tid=0x000000001eb16000 nid=0x8ac8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #12 daemon prio=9 os_prio=2 tid=0x000000001ea92800 nid=0x67b4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #11 daemon prio=9 os_prio=2 tid=0x000000001ea8f800 nid=0x5c68 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #10 daemon prio=9 os_prio=2 tid=0x000000001ea8f000 nid=0x6b4c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #9 daemon prio=9 os_prio=2 tid=0x000000001ea8d800 nid=0x7974 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Command Reader" #8 daemon prio=10 os_prio=0 tid=0x000000001ea53800 nid=0x3634 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Event Helper Thread" #7 daemon prio=10 os_prio=0 tid=0x000000001ea4d800 nid=0x86e0 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Transport Listener: dt_socket" #6 daemon prio=10 os_prio=0 tid=0x000000001ea41000 nid=0x540 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001e9e6000 nid=0x83a0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001e9e5000 nid=0x8dec runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001d2eb800 nid=0x8670 in Object.wait() [0x000000001fd1f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076c3862f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
- locked <0x000000076c3862f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001d2ea000 nid=0x8ba4 in Object.wait() [0x000000001fc1e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076c385d68> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
- locked <0x000000076c385d68> (a java.lang.ref.Reference$Lock)
"VM Thread" os_prio=2 tid=0x000000001e9a1800 nid=0x6398 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003670000 nid=0x7e64 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000003671800 nid=0x8218 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000003673000 nid=0x7830 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000003674800 nid=0x8e8c runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000003676800 nid=0x8114 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000003678000 nid=0x8220 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x000000000367b000 nid=0x6fc0 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x000000000367c000 nid=0x26d8 runnable
"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x000000000367d800 nid=0x8238 runnable
"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x000000000367e800 nid=0x82a4 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x000000001eb18000 nid=0x8900 waiting on condition
JNI global references: 4894
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x000000001d2f21b8 (object 0x000000076c88add0, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000001d2ef668 (object 0x000000076c88ade0, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at cn.net.cdsz.ccb.test.TestDeadLock$Thread2.run(TestDeadLock.java:46)
- waiting to lock <0x000000076c88add0> (a java.lang.Object)
- locked <0x000000076c88ade0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at cn.net.cdsz.ccb.test.TestDeadLock$Thread1.run(TestDeadLock.java:26)
- waiting to lock <0x000000076c88ade0> (a java.lang.Object)
- locked <0x000000076c88add0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
以上jstack.text内容的最后:
可以清晰的看到:
Thread-1获取了 <0x000000076c88ade0> 的锁,等待获取 <0x000000076c88add0> 这个锁
Thread-0获取了 <0x000000076c88add0> 的锁,等待获取 <0x000000076c88ade0> 这个锁
由此可见,发生了死锁。
避免死锁的几个常见方法
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
参考:【JVM】面试题之死锁及问题是怎么定位_jvm线程锁定定位_it噩梦的博客-CSDN博客