线程在操作系统使用不同的资源,一般以以下方式使用这些资源。
1)请求一个资源。
2)使用这个资源。
3)释放资源。
1、什么是死锁?
死锁的情况是,一些线程被阻塞,每个线程都拥有一个资源,并且等待另外一个进程以获取另外的一个资源。
想了想类似于生活中的哪些情形,我拥有有一本书(资源使用)叫做《java并发编程》 ,你拥有一本叫《java虚拟机》,我需要你的才能把java理解的更好,你也需要我的书,我们都各自拥有一本,但都需要得到对方的书籍而完成某个“学习线程”,我等待着你使用完你的书籍,你也等待着我使用完我的本书,便互相等待, 形成了死锁。(互相等待对方的资源,形成死循环,也许例子不太恰当)
相同的情形在操作系统中,当两个或者多个线程拥有一些资源,并且等待其他下线程拥有的资源。
例如如下图所示,线程1拥有资源1并且等待被线程2拥有的资源2, 而线程2拥有资源2但是,等待被线程1拥有的资源。
出现死锁的四个条件:
互斥:
线程的共享资源,为了线程安全可能需要同步(例如synchronized),也就是同一时刻只能有一个线程使用这个资源。
在某一个时刻这个资源只能被一个线程使用。
拥有锁和等待:
一个线程至少拥有一个资源,并且等待其他资源。
不能强占资源:一个线程不能获取一个资源,除非另外一个线程释放这个资源。
循环等待:
一些线程互相等待对方释放资源,形成死循环。
2、解决死锁的办法?
1)避免死锁和预防死锁,不让系统陷入死锁状态。
2)忽略死锁问题,如果死锁问题是非常罕见的,就让他发生并重启系统。这是windows和unix广泛采取的方法。
3)
If you need to have multiple locks in your code, make sure everyone always acquire them in the same order.
如果在代码中需要多个锁,确保代码每次请求他们的时候以相同的次序。
避免嵌套锁。只需要所动需要锁定的东西,而不是整个对象,如果符合我们的要求。
下面是典型的死锁例子,如下代码。
package deadlock;
/**
* `Created by fang on 2017/12/8.
* 死锁简单示例.伪代码
*/
public class DeadLockDemo {
public void methodA(){
synchronized (lockA){
//.....
synchronized (lockB){
//...
}
}
}
public void methodB(){
synchronized (lockB){
//....
synchronized (lockA){
//......
}
}
}
}
如上述伪代码,如果被多个线程调用可能会产生死锁。这是因为对象 A B 以不同的次序锁定。
这是绝大多数的死锁的原因,所以想要避免他们,保证这些对象锁是按顺序进行的。
上述代码我们这么解决死锁呢?
上述根源是锁的顺序不对,对共享资源的锁形成了循环等待,我们只需要按照同样的次序锁定就了。
解决方案伪代码如下。
//避免死锁的伪代码.
public void methodA(){
synchronized (lockA){
//.....
synchronized (lockB){
//...
}
}
}
public void methodB(){
synchronized (lockA){
//....
synchronized (lockB){
//......
}
}
}
我们对对象A B加锁两个方法并一致的锁的次序,解决了死锁问题。
下篇再说一下,死锁的解决方案,生产者和消费者模式。
小思:
自己不要死锁自己,容易死循环,也要多线程,时间分片执行任务。
效率才是王道,如何提高自己的效率? 就是间作,”农作物间作套种方式”。