发生死锁有4个必要条件,4个条件缺一不可:
1、互斥条件,共享资源在同一时刻只能被一个线程占用。
2、保持与请求条件,请求一把锁的时候还保持着另一把锁。
3、循环条件,线程的锁之间存在等待环路。
4、不剥夺条件,没有外界条件干扰锁的获取与释放。
下面是一个死锁的例子
class DeadLockDemo implements Runnable{
int flag = 1;
static Object lock1 = new Object();
static Object lock2 = new Object();
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"线程运行");
if (flag == 1) {
synchronized (lock1) {
Thread.sleep(500);
synchronized (lock2) {
System.out.println("线程1成功拿到两把锁");
}
}
}else if (flag == 0) {
synchronized (lock2) {
Thread.sleep(500);
synchronized (lock1) {
System.out.println("线程2成功拿到两把锁");
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
DeadLockDemo dl1 = new DeadLockDemo();
DeadLockDemo dl2 = new DeadLockDemo();
dl1.flag=1;
dl1.flag=0;
Thread t1 = new Thread(dl1);
Thread t2 = new Thread(dl2);
t1.start();
t2.start();
}
}
一段代码用到了多个锁,要避免以相反的顺序获取锁。如果死锁真的发生了,该如何检查出死锁呢?java提供了查找因死锁而阻塞的线程的方法。
ThreadMXBean是Java虚拟机线程系统的管理接口,Java虚拟机也提供了此接口的实现类,通过ManagementFactory.getThreadMXBean()获取实现类实例。使用findDeadlockedThreads()查找因死锁而阻塞的线程。
class DeadLockDemo implements Runnable{
int flag = 1;
static Object lock1 = new Object();
static Object lock2 = new Object();
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"线程运行");
if (flag == 1) {
synchronized (lock1) {
Thread.sleep(500);
synchronized (lock2) {
System.out.println("线程1成功拿到两把锁");
}
}
}else if (flag == 0) {
synchronized (lock2) {
Thread.sleep(500);
synchronized (lock1) {
System.out.println("线程2成功拿到两把锁");
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
DeadLockDemo dl1 = new DeadLockDemo();
DeadLockDemo dl2 = new DeadLockDemo();
dl1.flag=1;
dl1.flag=0;
Thread t1 = new Thread(dl1);
Thread t2 = new Thread(dl2);
t1.start();
t2.start();
// 睡眠1秒钟确保死锁发生
TimeUnit.SECONDS.sleep(1);
/**
* 使用ThreadMXBean查找因死锁而阻塞的线程
*/
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] dlt = threadMXBean.findDeadlockedThreads();
if (dlt != null){
for (int i=0; i<dlt.length; i++){
ThreadInfo threadInfo = threadMXBean.getThreadInfo(dlt[i]);
System.out.println("发现因死锁而阻塞的线程 "+threadInfo.getThreadName());
}
}
}
}