什么是线程死锁
线程死锁描述的是这样⼀种情况:多个线程同时被阻塞,它们中的⼀个或者全部都在等待某个资源被释放。由于线程被⽆限期地阻塞,因此程序不可能正常终⽌。假如线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对⽅的资源,所以这两个线程就会互相等待⽽进⼊死锁状态。
产⽣死锁必须具备的四个条件
- 互斥条件:该资源任意⼀个时刻只由⼀个线程占⽤。
- 请求与保持条件:⼀个进程因请求资源⽽阻塞时,对已获得的资源保持不放。
- 不剥夺条件:线程已获得的资源在末使⽤完之前不能被其他线程强⾏剥夺,只有⾃⼰使⽤完毕后才释放资源。
- 循环等待条件:若⼲进程之间形成⼀种头尾相接的循环等待资源关系。
如何避免线程死锁(破坏条件)
- 破坏互斥条件 :这个条件我们没有办法破坏,因为我们⽤锁本来就是想让他们互斥的(临界资源需要互斥访问)。
- 破坏请求与保持条件 :⼀次性申请所有的资源。
- 破坏不剥夺条件 :占⽤部分资源的线程进⼀步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
- 破坏循环等待条件 :靠按序申请资源来预防。按某⼀顺序申请资源,释放资源则反序释放。破坏循环等待条件。
死锁代码模拟
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* 死锁
*
*/
public class DeadLockDemo {
private static final Object RESOURCE1 = new Object();
private static final Object RESOURCE2 = new Object();
public static void main(String[] args) {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(10, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
singleThreadPool.execute(() -> {
synchronized (RESOURCE1) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "持有resource1,等待resource2中...");
synchronized (RESOURCE2) {
System.out.println(Thread.currentThread().getName() + "得到了resource2");
}
}
});
singleThreadPool.execute(() -> {
synchronized (RESOURCE2) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "持有resource2,等待resource1中...");
synchronized (RESOURCE1) {
System.out.println(Thread.currentThread().getName() + "得到了resource2");
}
}
});
}
}
demo-pool-1持有resource2,等待resource1中…
demo-pool-0持有resource1,等待resource2中…