Java基础(33)——多线程相关知识详解及示例分析五(线程死锁)

Java基础(33)——多线程相关知识详解及示例分析五(线程死锁)


版权声明

  • 本文原创作者:清风不渡
  • 博客地址:https://blog.csdn.net/WXKKang

  上面我们讲到了Java中线程互斥的机制,那就是给线程访问的数据上锁,那么这样就一定安全吗?答案肯定是否定的,这个世界上没有绝对安全的东西,而上篇所讲到的方法就会出现线程死锁的现象,那么这个现象是什么意思呢?我们该怎样处理或者说怎样避免发生这样的现象呢?下面我们就来一一学习吧

一、线程死锁

  多线程中使用锁会造成效率低,如果出现了同步嵌套,就容易产生死锁问题
  死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
  如果两个线程之间有多个共享对象,如果两个线程分别持有对方所需要的共享对象的锁,在试图获取对方线程所持有的共享对象的锁时,就有死锁的危险

1、死锁产生的原因

  加入我们现在有两个线程(线程1与线程2),这两个线程之间有两个共享对象(对象A和对象B),在线程执行的过程中,线程1与线程2都必须同时获得对象A与对象B后才能正常工作
  那么当线程1获得了对象A的锁、线程2获得了对象B的锁,如果两个线程都不释放所获得的对象的锁,那么线程1将不能得到对象B的锁,线程2将不能得到对象A的锁,这种情况下两个线程都将被阻塞,即所谓的死锁
在这里插入图片描述

2、死锁的解决方案

  死锁通常是由于资源的无序使用,导致线程不能得到正常执行所需要的资源
  解决死锁问题的方法,就是所有线程使用一致的顺序申请资源锁。例如:
  1、线程1和线程2都是按照对象A、对象B的顺序来获得对象锁
  2、将对象A编号为1,对象B编号为2,线程1和线程2都必须先获得1号资源后方可再获取2号资源

3、死锁示例

  下面我们来演示一个发生死锁的例子,这里有四个对象:艺术家、画匠、笔、纸。艺术家、画匠在工作时都需要同时有笔、纸  死锁演示效果:
  1、艺术家首先得到笔,然后再去获取纸;工匠首先得到纸,然后再去获取笔
  2、由于艺术家和工匠都不愿意放弃自己获得的笔、纸,因此二者都不能同时获得笔和纸,因此都无法工作

  代码如下:

package qfbd.com;
/*
原创作者:清风不渡
博客地址:https://blog.csdn.net/WXKKang
*/
public class Demo {

	public static void main(String[] args) throws Exception {
		Resource resource = new Resource();
		
		//创建艺术家对象
		Artist artist = new Artist();
		artist.prepace(resource);
		
		//创建工匠
		Limner limner = new Limner();
		limner.prepace(resource);
		
		//这里一定要先启动艺术家才能有死锁情况
		artist.start();
		limner.start();
	}
}

//笔类
class Pen{
	
}
//纸类
class Paper{
	
}
//共享的资源类,这里同时有笔和纸
class Resource{
	private Pen pen = new Pen();
	private Paper paper = new Paper();
	
	public Paper getPaper(){
		return paper;
	}
	
	public Pen getPen(){
		return pen;
	}
}

/*
 * 艺术家
 * 
 * 这是一个线程类,在线程体中有两个同步块,分别是对pen和paper对象进行同步
 */
class Artist extends Thread {
	private Resource resource;
	
	@Override
	public void run() {
		Pen pen = resource.getPen();
		System.out.println("艺术家获得笔!!!");
		
		synchronized (pen) {
			/*
			 * 加入睡眠原因:
			 * 1、在运行线程时,艺术家线程先执行,他首先获得笔
			 * 2、如果没有这个睡眠,那么可能画匠还没来的及获取到纸,
			 * 	    艺术家线程就获取到了纸,这样就无法测试死锁的情形了
			 */
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				System.out.println("艺术家睡眠发生异常!!!");
			}
			//睡眠之后获取纸,但预测纸已经被画匠获取到了,此刻进入等待
			Paper paper = resource.getPaper();
			synchronized (paper) {
				System.out.println("艺术家可以画画了!!");
			}
			
		}
	}
	
	public void prepace(Resource resource){
		this.resource = resource;
	}
}

/*
 * 画匠
 * 
 * 这是一个线程类,在线程体中有两个同步块,分别是对paper和pen对象进行同步
 * 注意:他的同步对象paper和pen的顺序和艺术家是相反的
 */
class Limner extends Thread{
	private Resource resource;
	
	@Override
	public void run() {
		Paper paper = resource.getPaper();
		System.out.println("画匠得到纸!!!");
		synchronized (paper) {
			//然后获取笔,预测被艺术家得到并睡眠,此刻进入等待
			Pen pen = resource.getPen();
			synchronized (pen) {
				System.out.println("画匠可以画画了!!!");
			}
		}
	}
	public void prepace(Resource resource){
		this.resource = resource;
	}
	
}

  执行结果如下:
在这里插入图片描述
  可以发现,程序运行“卡死了”,即发生了所谓的死锁现象

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章