JAVA多线程系列-8-死锁

2016/06/03 Java

多个线程进行资源竞争,资源的同步不当,便会引发程序的无限等待,即是我们所说的死锁。 本章讲述死锁的原理,以“哲学家就餐问题”进行死锁举例,以及提出避免死锁一些方法。

死锁的概念

两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

死锁条件:

  • 1:互斥条件:线程占有资源的互斥访问。
  • 2:请求与保持条件:线程至少拥有一个资源,但又需要其他资源,进而阻塞。
  • 3:不可剥夺条件:线程已获得的资源,在使用完之前,不可以强行剥夺,只能自己释放。
  • 4:循环等待条件:若干进程请求的资源

死锁模型-哲学家就餐问题

死锁模型: 哲学家就餐问题:

/*
 * 死锁模拟,哲学家就餐问题的简单实现
 * 
 * 
 * @author 徐兵
 */

public class DeadLock {
	public static void main(String arg[])
	{
		DeadLock dead = new DeadLock();
		Thread t1=new Thread((new DeadLock()).new MyRunnable1(dead),"t1");
		Thread t2=new Thread((new DeadLock()).new MyRunnable1(dead),"t2");
		t1.start();
		t2.start();
	}
	
	public class MyRunnable1 implements Runnable
	{
		DeadLock dead =new DeadLock();
		public  MyRunnable1(DeadLock dead) {
			this.dead=dead;
		}
		
		@Override
		public void run() {
			dead.write(1, 2);
			dead.read();
		}
	}
	
	public class MyRunnable2 implements Runnable
	{
		DeadLock dead =new DeadLock();
		public  MyRunnable2(DeadLock dead){
			this.dead=dead;
		}
		@Override
		public void run() {
			dead.read();
			dead.write(1, 2);
		}
	}

    private String resourceA =new String();//资源,注意:要为同一对象
    private String resourceB =new String();

    public void  read() {
        synchronized (resourceA) {
    		System.out.println("getA");
        	try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
            synchronized (resourceB) {
        		System.out.println("getB");
            } 
        } 
    } 

    public void write(int a,int b) { 
        synchronized (resourceB) {
    		System.out.println("getB ");
        	try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
            synchronized (resourceA) {
        		System.out.println("getA");
            } 
        } 
    } 
}

哲学家就餐死锁 https://github.com/xnzaa/xnzaa.github.io/raw/master/_images/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/RegexCpp.png

针对哲学家就餐问题,也存在很多解决方法,目前被大家所认可的是下面3种方法:

服务生法、资源分级法、Chandy/Misra法(哲学家沟通法)

死锁避免的3种方法

  • 死锁的预防
  • 死锁的避免
  • 死锁的检测与忽略

银行家算法

银行家算法源代码及其解释

银行家算法是一种预分配算法,银行家类似操作系统,线程所需的资源就好比银行里的钱,线程申请资源好比是从银行里贷款。
当进程首次申请资源时,操作系统会测试进程所需的最大资源,若超过系统现有资源的总和,则推迟分配,否者正常分配。
当进程运行中再次申请资源时,操作系统会判断 (这次资源的申请量)+(进程已占有的资源量)>(进程的最大需求量)? 如超过则拒绝分配。 若没超过,再比较本次申请的资源与系统目前的资源总量,若超过,则推迟分配,否者正常分配。

银行家算法有一个很大的问题就是,需要预先知道程序所需的所有资源!



/*
 * 银行家算法模拟
 * 
 * @author 徐兵
 */


public class ProblemBanker {
	
	//这个算法没写!
	//主要原因:算法思想本身的编程实现,使用模拟资源,线程调度内容无关,所以没写!
	//次要原因:我懒~
	//哈哈,你来完成,怎么样?
}

当然,还存在很多其他解决死锁的方法:比如一次性分配等,但是都会不同程度地降低程序的并发性,降低效率!

上一章: 同步互斥及模型实现

下一章: 其他

Search

    Post Directory