作者简介: zoro-1,目前大二,正在学习Java,数据结构,javaee等
作者主页: zoro-1的主页
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖
线程安全问题之死锁
- 一个线程,一把锁
- 两个线程,两把锁
- M个线程,M把锁
- 陷入死锁的四个必要条件
- 解决死锁的方案
一个线程,一把锁
public class ThreadText6 {
public static void main(String[] args) {
Object object=new Object();
Thread thread=new Thread(()->{
synchronized (object){//(A)
synchronized (object){//(B)
System.out.println(1);
}//(C)
}//(D)
});
thread.start();
}
}
在这个代码中,直观来看会产生锁冲突,最外层获取锁内层获取到锁时会产生阻塞,因为外层的锁还未释放,但JAVA中的synchronized锁是一个可重入锁(当线程已经持有锁时,它可以再次获取同一个锁,而不会被阻塞。这种锁可以在同一线程中被多次获取和释放,而不会出现死锁的情况,因为它会记录当前线程已经获取锁的计数器),第一次加锁时(A处),计数器加1,第二次加锁(B处)是同一个对象就直接计数器+1然后(C处)计数器减1,然后(D处)计数器归零,真正释放锁;
两个线程,两把锁
public class ThreadText7 {
public static void main(String[] args) {
Object A = new Object();
Object B = new Object();
Thread thread = new Thread(() -> {
synchronized (A) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (B) {
System.out.println("thread拿到两把锁");
}
}
});
Thread thread1 = new Thread(() -> {
synchronized (B) {
synchronized (A) {
System.out.println("thread1拿到两把锁");
}
}
});
thread.start();
thread1.start();
}
}
线程thread获取到A锁,然后休眠1000ms(确保thread1能获取到B锁),然后随机调度,可能thread尝试获取到B锁,也可能thread1尝试获取A锁但两个线程都获取不到,因为互相都没释放锁,就陷入永久的阻塞状态
M个线程,M把锁
一个经典的案例(哲学家就餐问题)
我们把每个小人看作一个线程,每根筷子看作一把锁,每个线程都要完成吃面条这个任务(拿起两个筷子),但现在有一个特殊情况,我们让所有小人同时拿起左手旁的筷子,然后再尝试获取右边的筷子,就获取不到了因为每个小人都持有一根筷子,且在未获取到第二个筷子前不会释放锁,就陷入永久的阻塞了
陷入死锁的四个必要条件
1.互斥作用:一个线程获取到锁了,另一个线程想要获取到这个锁就要等到他释放
2.不可抢占性:一个线程获取到锁后只能主动释放不会被别的线程抢走
3.请求保持:一个线程在有一个锁的情况下,尝试获取其他的锁
4.循环等待/环路等待
解决死锁的方案
就M个线程,M把锁来说有:
1.额外加入筷子
2.去掉一个线程
3.引入计数器,限制最多多少人同时吃面
4.引入加锁顺序规则,将锁编好号,按从小到大加锁,只能拿左右手编号小的锁(最常用的一种)
用四方法解决两个线程,两把锁的问题就是(规定只能两个线程都只能先拿A,再拿B):
public class ThreadText7 {
public static void main(String[] args) {
Object A = new Object();
Object B = new Object();
Thread thread = new Thread(() -> {
synchronized (A) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (B) {
System.out.println("thread拿到两把锁");
}
}
});
Thread thread1 = new Thread(() -> {
synchronized (A) {
synchronized (B) {
System.out.println("thread1拿到两把锁");
}
}
});
thread.start();
thread1.start();
}
}
>今天的分享到这就结束了,感谢大家支持