线程的死锁和死锁解决的实际案例
尊重劳动成果,本文是参照https://blog.csdn.net/qq_38638148/article/details/82725191 然后再结合我自己的理解整理的,感谢博主的辛苦付出
造成死锁的原因:
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
死锁的解除:一旦检测出死锁,就应立即釆取相应的措施,以解除死锁。死锁解除的主要两种方法:
(1)抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态。
(2)终止(或撤销)进程。终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态解脱出来。
先来看死锁:就是多个锁和多个线程之间发生的故事,这里以俩个锁和俩个线程为例子。
锁1、锁2、线程1、线程2
当线程1获取锁1之后,线程2也获取了锁2,这是线程1又开始获取锁2(嵌套获取),线程2又想获取锁1(嵌套1获取),这种情况下线程1会等着线程2释放锁2,线程2会等着线程1释放锁1,然后就会形成了死锁。
具体代码:
public class deadLock implements Runnable{
//1.创建俩把锁
public static final Object object1=new Object();
public static final Object object2=new Object();
boolean boo;
@Override
public void run() {
if(boo) {
synchronized (object1) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object2) {
System.out.println("进入2锁");
}
}
}else {
synchronized(object2) {
System.out.println("进入2锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入1锁");
}
}
}
}
}
测试代码
public static void main(String[] args) {
deadLock d1=new deadLock();
deadLock d2=new deadLock();
d1.boo=true;
d2.boo=false;
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
}
怎么解决呢?
这种解决方式可以有三种,
1.顺序取锁
2.设置锁释放时间(可以使用Lock来实现)
3.预防死锁
接下来贴出第一个方式的代码:
public class openLock implements Runnable{
public static final Object object=new Object();
public static final Object object1=new Object();
boolean bool;
@Override
public void run() {
if(bool) {
synchronized (object) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入二锁");
}
}
}else {
synchronized (object) {
System.out.println("进入1锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("进入2锁");
}
}
}
}
}
对比死锁的代码来看,其实就是让所有的线程获取所得顺序是一样的,这样子的话就不会存在什么线程死锁的情况出现。
第二种方法
public class OpenLock implements Runnable{
//第二种解决死锁的方式是:给锁设置一个时间,如果超过这个时间的或就放弃获取这个锁。
Lock l1=new ReentrantLock();//锁1
Lock l2=new ReentrantLock(); //锁2
boolean bool;
@Override
public void run() {
if(bool) {
try {
l1.lock();
System.out.println("加上锁1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("现在我在等待进入锁二了");
if(l2.tryLock(200, TimeUnit.MILLISECONDS)){//注意在判断这一步就已经加上锁了
try {
System.out.println("进入锁二");
}finally {
l2.unlock();
}
}else{
System.out.println("锁二一直被占用,算了我不进去了");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
l1.unlock();
}
}else {
l2.lock();
try {
System.out.println("进入锁二");
Thread.sleep(1000);
System.out.println("现在我在等待进入锁1了");
if(l1.tryLock(200,TimeUnit.MILLISECONDS)) {
try {
System.out.println("进入锁一");
}finally {
l1.unlock();
}
}else {
System.out.println("等带时间太长了,我不等了。");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
}
}
}
}
这种方法就是利用Lock来实现的,Lock锁有一种说法叫做可中断锁,意思是当等待的线程达到一定的时间之后,就不会再去等待了,它会放弃运行这个锁方法,而去执行其他方法。