ava多线程中经常需要对同一资源的访问进行限制。实现这种同步方式的机制有很多种。如:sychronized,Semaphore,ReentrantLock。
但是针对一个线程需要获取多个资源的锁的时候 ,容易发生死锁的情况。如
package com.winston.thread.deadlock;
/**
*
* @Description: 线程死锁
*
* @version: v1.0.0
* @author: Winston
* @date: 2018年8月28日 下午3:47:32
*/
public class TestDeadLock {
public static void main(String[] args) {
String lock1 = "aa";
String lock2 = "bb";
Thread thread1 = new Thread(new MyThread1(lock1, lock2));
Thread thread2 = new Thread(new MyThread1(lock2, lock1));
thread1.setName("thread1");
thread2.setName("thread2");
thread1.start();
thread2.start();
}
}
class MyThread1 implements Runnable {
private String lock1;
private String lock2;
public MyThread1(String lock1, String lock2) {
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "获得:" + lock1);
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "等待:" + lock2);
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "获得:" + lock2);
}
}
}
}

本例中thread1获得:aa对象的锁,然后休眠了3秒钟。并且此间thread2获得:bb对象的锁。也休眠了3秒钟。当两个线程休眠结束的时候再接着获取第二个对象锁。对于thread1等待aa对象锁,thread2等待bb对象锁的时候 就发生了死锁。
使用jps工具查看机器上运行的java进程。(当本地启动多个Tomcat的时候 使用jps会只打印出Tomcat的启动类名,无法对应进程号和具体应用。使用jps -lv会打印应用的完整路径名和传给jvm的参数。linux 上面可以使用 ps -aux|grep java)
C:\Users\Winston>jps -lv
10384 -Dosgi.requiredJavaVersion=1.8 -Dosgi.instance.area.default=@user.home/eclipse-workspace -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Xms256m -Xmx1024m
7712 -Dosgi.requiredJavaVersion=1.8 -Dosgi.instance.area.default=@user.home/eclipse-workspace -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Xms256m -Xmx1024m
47268 sun.tools.jps.Jps -Dapplication.home=C:\Program Files\Java\jdk1.8.0_152 -Xms8m
20776 com.winston.thread.deadlock.TestDeadLock -Dfile.encoding=UTF-8
使用jstack获取堆内存快照 用法:jstack pid
C:\Users\Winston>jstack 20776
2018-08-28 16:16:37
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):
"DestroyJavaVM" prio=6 tid=0x0000000002bae000 nid=0x290 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"thread2" prio=6 tid=0x000000000d363000 nid=0x55e4 waiting for monitor entry [0x000000000d9bf000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.winston.thread.deadlock.MyThread1.run(TestDeadLock.java:52)
- waiting to lock <0x00000007d63d88a8> (a java.lang.String)
- locked <0x00000007d63d88d8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
"thread1" prio=6 tid=0x000000000d360800 nid=0x3314 waiting for monitor entry [0x000000000d8be000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.winston.thread.deadlock.MyThread1.run(TestDeadLock.java:52)
- waiting to lock <0x00000007d63d88d8> (a java.lang.String)
- locked <0x00000007d63d88a8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
"Service Thread" daemon prio=6 tid=0x000000000b450000 nid=0x5394 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=10 tid=0x000000000b44c800 nid=0x51c0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=10 tid=0x000000000b445000 nid=0x51fc waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" daemon prio=10 tid=0x000000000b444000 nid=0x500c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x000000000b443000 nid=0x3438 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=8 tid=0x000000000301b000 nid=0x54ac in Object.wait() [0x000000000cdbf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d6284858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000007d6284858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" daemon prio=10 tid=0x000000000b407000 nid=0x5154 in Object.wait() [0x000000000ccbe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d6284470> (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 <0x00000007d6284470> (a java.lang.ref.Reference$Lock)
"VM Thread" prio=10 tid=0x000000000b403000 nid=0x1404 runnable
"GC task thread#0 (ParallelGC)" prio=6 tid=0x0000000002f46800 nid=0x42a0 runnable
"GC task thread#1 (ParallelGC)" prio=6 tid=0x0000000002f49800 nid=0x50c8 runnable
"GC task thread#2 (ParallelGC)" prio=6 tid=0x0000000002f4b000 nid=0x51b4 runnable
"GC task thread#3 (ParallelGC)" prio=6 tid=0x0000000002f4c800 nid=0x2218 runnable
"GC task thread#4 (ParallelGC)" prio=6 tid=0x0000000002f4f000 nid=0x15c4 runnable
"GC task thread#5 (ParallelGC)" prio=6 tid=0x0000000002f50800 nid=0x40fc runnable
"VM Periodic Task Thread" prio=10 tid=0x000000000d2c8800 nid=0x41d4 waiting on condition
JNI global references: 108
Found one Java-level deadlock:
=============================
"thread2":
waiting to lock monitor 0x000000000301ab78 (object 0x00000007d63d88a8, a java.lang.String),
which is held by "thread1"
"thread1":
waiting to lock monitor 0x0000000003019838 (object 0x00000007d63d88d8, a java.lang.String),
which is held by "thread2"
Java stack information for the threads listed above:
===================================================
"thread2":
at com.winston.thread.deadlock.MyThread1.run(TestDeadLock.java:52)
- waiting to lock <0x00000007d63d88a8> (a java.lang.String)
- locked <0x00000007d63d88d8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
"thread1":
at com.winston.thread.deadlock.MyThread1.run(TestDeadLock.java:52)
- waiting to lock <0x00000007d63d88d8> (a java.lang.String)
- locked <0x00000007d63d88a8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
C:\Users\Winston>
thread2
- waiting to lock <0x00000007d63d88a8> (a java.lang.String)
- locked <0x00000007d63d88d8> (a java.lang.String)
thread1
- waiting to lock <0x00000007d63d88d8> (a java.lang.String)
- locked <0x00000007d63d88a8> (a java.lang.String)
线程thread2 等待的0x00000007d63d88a8被thread1 locked 。
其实工作中肯定不会编写以上代码。一般产生死锁的情况,都是因为程序缺陷导致的。
使用Lock的tryLock()方法也可以避免死锁的情况。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

Java多线程中常需对同一资源访问进行限制,有sychronized等多种同步机制。但一个线程获取多个资源锁时易发生死锁,如示例中thread1和thread2休眠后获取锁的情况。可使用jps查看进程,jstack获取堆内存快照,还可用Lock的tryLock()方法避免死锁。
1066

被折叠的 条评论
为什么被折叠?



