死锁
怕艾兵豪斯的遗忘曲线提前来,先mark一下
简单的说:两个线程在持有自己的锁的情况下需要彼此手中的锁(中的资源),彼此不放手,那么就一直在等待对方释放手中的锁,永远的等待~导致了死锁
示例:
public class Test {
public static void main(String[] args) {
// 死锁演示
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread, "1");
Thread thread1 = new Thread(myThread, "2");
thread.start();
thread1.start();
}
static class MyThread implements Runnable {
// 同步代码块中要保证锁对象一致,否则跟没有锁一样,达不到数据同步的效果
Object lock = new Object();
@Override
public void run() {
if (Thread.currentThread().getName().equals("1")) {
synchronized (lock) {
try {
// 让线程睡一下的目的是为了保证后进行的线程能拿到锁
(cpu处理太快,也即是后执行的线程还没拿到锁的时候,先执行的线程就已经执行完毕,
并将资源和锁释放了,后执行的线程就会照常执行)
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
say("1");
}
} else {
say("2");
}
}
private synchronized void say(String name) {
synchronized (lock) {
// 同上
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"我执行了");
}
}
}
}
这里要注意一下:测试死锁的显示,要在psvm主方法的环境下运行才能看到死锁的发生,如果是使用单元测试来测试死锁则会没有效果,具体原因目前还不清楚
发生条件:
①:互斥:一个线程获得资源后,另一个需要相同资源的线程只能等待(阻塞)
②:线程中的锁只能通过自己释放,外界无法干预
③:请求与保持:线程未完成前,自己持有的锁(资源)也不会主动释放
④:线程之间循环等待
(死循环,这里联想到了jdk1.7中的HashMap的死循环,在1.8中已经解决(通过加锁))
满足上面的所有条件就会发生死锁
如何避免:个人认为上述条件之一不成立即可
ps:可重入锁可以有效的解决该问题:线程1如果已经获得过一次锁,资源就会记录该线程,下一次又来获取锁(资源)的时候,如果发现其他的线程也在竞争同一个锁(资源),为了避免死锁的发生,线程1就会主动放弃该锁,以及自己持有的资源,让其他线程先使用,待有空当之后再完成自己的事情,从而避免死锁,当中保持自旋。
有一个比较粗俗的例子:小明去上厕所,发现厕所里面已经满了,要么在厕所里等,要么在外面等,如果在里面等,不仅会影响后面进来的人,还要感受“芳香”,实在没有必要,不如直接在外面等,玩会手机/抽烟,一旦有人出来再进去就好。
2019.12.17:补充,这里重新定义对可重入锁的概念:第一次看的时候以为就是上面的定义,但最近重新了解了可重入锁之后,发现好像和一开始认识的可重入锁截然不同。
就目前来说,我对可重入锁(又称递归锁)的理解是:当对象中的多个方法都存在锁机制时,当某一线程抢夺到了最外层的方法的锁时,它就能顺理成章的接着进行内层中还存在了锁的代码块,也就是一方通行!
感想:看着容易理解,但实际敲一遍效果和看一遍还是有天壤之别的,这也说明了理论和实践同样重要,希望能坚持每天写!
ps:还在学习中,希望大牛们发现上面理解和代码中存在的问题能在评论中指出~感谢
(没有感情的复制怪~)
引用:https://blog.csdn.net/lixinkuan328/article/details/94416483