死锁的三种条件
1.一个线程一把锁
当一个线程尝试重复获取锁,如果该锁不是可重入锁,则会尝生死锁
(图中的synchronized是可重入锁)
public class Demotest {
public static void main(String[] args) {
Object lock=new Object();
synchronized (lock){
synchronized (lock)
{
while(true)
{
System.out.println("Hello");
}
}
}
}
}
2.两个线程两把锁
当A获取到锁1,B获取到锁2
而A尝试获取锁2,B尝试获取锁1,产生死锁
public class Demotest {
public static void main(String[] args) {
Object lock1=new Object();
Object lock2=new Object();
Thread t1=new Thread(()->
{
synchronized (lock1)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println("t1");
}
}
});
Thread t2=new Thread(()->
{
synchronized (lock2)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1){
System.out.println("t2");
}
}
});
t1.start();
t2.start();
}
}
3.N个线程N把锁
哲学家就餐问题
:五个哲学家围坐在一张桌子附近,每人前面有一碗意面,共有五把叉子,每个哲学家需要左右手 同时拿起叉子才能就餐,且哲学家会在思考和就餐这两种状态进行交替。当五个哲学家同时拿起右手边的叉子,当准备去拿左手边的叉子时,就会造成死锁的情况。
死锁产生的四个必要条件
1.互斥使用:该资源任意时刻只由一个线程占有。
2.不可抢占:该线程使用资源过程中不能被其它线程所剥夺,只有使用完后才能释放资源。
3.请求和保持:该线程因其它请求资源而阻塞的时候,保持对原有资源的占有。
4.循环等待:若干线程形成首尾相接的循环等待资源的关系。
其中循环等待是最容易出现的问题
打破循环等待的方法:给锁进行编号,当多把锁的时候,约定锁的顺序,如以下代码就产生了循环等待。
public class Demotest {
public static void main(String[] args) {
Object lock1=new Object();
Object lock2=new Object();
Thread t1=new Thread(()->
{
synchronized (lock1)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println("t1");
}
}
});
Thread t2=new Thread(()->
{
synchronized (lock2)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1){
System.out.println("t2");
}
}
});
t1.start();
t2.start();
}
}
将代码改为即可
public class Demotest {
public static void main(String[] args) {
Object lock1=new Object();
Object lock2=new Object();
Thread t1=new Thread(()->
{
synchronized (lock1)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println("t1");
}
}
});
Thread t2=new Thread(()->
{
synchronized (lock1)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2){
System.out.println("t2");
}
}
});
t1.start();
t2.start();
}
}