死锁
当两个线程互相等待对方释放同步监视器时会发生死锁,通俗来讲就是A线程占用自己资源的同时在等待B线程释放资源,而B线程占用自己资源的同时在等待A线程释放资源,从而发生死锁。
当出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。应避免这种情况出现:
- 避免多次锁定
尽量避免同一个线程对多个同步监视器进行锁定; - 按相同的顺序加锁
如果多个线程需要对多个同步监视器加锁,则因保证它们以相同的顺序请求加锁; - 可以使用超时释放发锁
调用Lock对象的tryLock(time,unit)方法,当超过指定时间后它会自动释放锁。
示例代码:
package com.nefu;
/** 死锁 */
public class ThreadDemo08 {
public static void main(String[] args) {
//创建两个对象
String a="A";
String b="B";
//同时启动两个线程
new Thread(new FirstTask(a,b)).start();
new Thread(new SecondTask(a,b)).start();
}
//利用实现Runnable接口的的方式创建一个线程FirstTask
private static class FirstTask implements Runnable {
//创建两个对象
private Object a;
private Object b;
//初始化对象属性
public FirstTask(Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (a){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//执行了10ms后需要对b加锁,使用其资源,但是b还在利用资源
synchronized (b){
System.out.println("First!");
}
}
}
}
//利用实现Runnable接口的的方式创建一个线程SecondTask
private static class SecondTask implements Runnable {
private Object a;
private Object b;
public SecondTask (Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (b){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//执行了10ms后需要对a加锁,使用其资源,但是a还在利用资源
synchronized (a){
System.out.println("Second!");
}
}
}
}
}
运行结果:
C:\Program Files\Java\jdk1.8.0\bin\java.exe"
//运行无任何结果,并且程序未停止,一直处于运行状态,需要手动停止,产生了”死锁“。
产生死锁的四个必要条件
- 互斥条件:一个资源每次只能宝贝一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系