死锁的产生
- 互斥条件:当资源被占用的时候,其他线程不能使用。
- 请求与保持:一个线程去请求资源,被阻塞时他所占有的资源是不会被释放的。
- 不可剥夺:线程以获取到一个资源在没有使用的情况下。不能被强行剥夺。
- 循环等待:t1线程占用o1要用o1,o2资源;t2资源占有o2要用o1,o2;
下面是死锁产生(循环等待)的一个例子:
public class DeadLock implements Runnable {
public String username;
public Object lock1 = new Object();
public Object lock2 = new Object();
public void setFlag(String username) {
this.username = username;
}
public void run() {
// TODO Auto-generated method stub
if (username.equals("a")) {
synchronized (lock1) {
try {
System.out.println("username" + username);
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("lock1_>lock2");
}
}
}
if (username.equals("b")) {
synchronized (lock2) {
try {
System.out.println("username" + username);
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("lock2->lock1");
}
}
}
}
public static void main(String[] args) {
DeadLock t1 = new DeadLock();
t1.setFlag("a");
Thread thread1 = new Thread(t1);
thread1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t1.setFlag("b");
Thread thread = new Thread(t1);
thread.start();
}
}
运行结果:
怎么查看死锁
在这里以上面的代码为例子介绍两个方法。
方法一
使用jps命令查看当前执行的线程。
使用jstack查看要查看线程的状态
可以看到图片的第一行发现一个死锁。
方法二
首先在jdk/bin目录下找到jvisualvm工具
打开工具找到可能有死锁的项目
它会提示检测到死锁如下图
点击进入"线程Dump"可以查看详细信息
思索的解除与预防
- 避免一个线程同时获取多个锁
- 避免一个线程所内占用多个资源
- 尝试使用定时所,即使用lock。tryLock()来代替使用内部锁机制
- 对于数据库锁加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。