死锁概念以及如何用java写一个死锁程序 - Go语言中文社区

死锁概念以及如何用java写一个死锁程序


死锁概念

死锁严格意义上的含义这里引用维基百科的解释:

在并发计算中,死锁是一种状态,其中组的每个成员正在等待另一个成员(包括其自身)采取行动,例如发送消息或更常见地释放锁定。[1]死锁是多处理系统,并行计算和分布式系统中的常见问题,其中软件和硬件锁用于仲裁共享资源并实现进程同步。
在操作系统中,当进程或线程进入等待状态时发生死锁,因为所请求的系统资源由另一个等待进程保持,而另一个等待进程又等待另一个等待进程持有的另一个资源。如果进程无法无限期地更改其状态,因为其请求的资源正由另一个等待进程使用,则系统被认为处于死锁状态。
在通信系统中,死锁主要是由于信号丢失或损坏而不是资源争用

简单的说,有两个进程A,B在执行过程中,A需要资源C,而C只有一份,只能被一个进程访问,现在C资源被B持有,而B也需要资源D,而D被A占有,这时A,B处于长时间的竞争中,都无法进行下去,这时就说系统处于死锁状态。
如下图:
在这里插入图片描述

两个进程都需要资源来继续执行。P1需要额外的资源R1并且拥有资源R2,P2需要额外的资源R2并且拥有R1 ; 两个过程都不​​能继续。

死锁必要条件

当且仅当以下所有条件同时存在于系统中时,才会出现资源上的死锁情况:

  • 相互排斥:系统中必须有非共享的资源,即在任何给定的时刻,只有一个进程可以使用该资源。
  • 保持等待:进程当前持有至少一个资源并请求其他进程持有的其他资源。
  • 不可抢占:资源只能由持有它的进程自愿释放,其他进程不可强行占有该资源。
  • 循环等待:每个进程必须等待另一个进程持有的资源,而该进程又等待第一个进程释放资源。

这四个条件被称为Coffman条件。

死锁处理

可以采用跟踪资源分配和进程状态的算法来检测死锁,大多数方法通过防止四种Coffman条件中的一种发生来预防死锁,尤其是第四种。

Java写死锁程序实例

设计思想:

  • 1.设置两个线程A,B,设置两个资源标记对象a,b,
  • 2.用A去锁住a,用B去锁住b,使a,b都被占有,
  • 3.这时再用A去锁b,表示A目前需要b资源,因b目前被B占有,此时A无法锁住b
  • 4.同理,用B去锁a,B也无法去锁住a,形成死锁,A,B陷于无限等待,形成死锁
public class DeadLock {
    public static Object a = new Object();
    public static Object b = new Object();
    
    public static void main(String[] args){
    	DeadLock d = new DeadLock();
    	d.setDeadlock();
    }    
    
    // 建立死锁
    private void setDeadlock() {
        Thread A = new Thread(new Runnable() {
            public void run() {
                threadA();
            }
        });
        Thread B = new Thread(new Runnable() {
            public void run() {
            	threadB();
            }	
        });
        A.start();
        B.start();
    }
    protected void threadA() {
    	synchronized (DeadLock.a) {
    		System.out.println("A keeps a");
            sleep();  // 留出时间让线程B去锁住b
        	synchronized (DeadLock.b) {
        		System.out.println("A got b");
                sleep();
            }

        }	
	}

    private void threadB() {
    	synchronized (DeadLock.b) {
    		System.out.println("B keeps b");
            sleep();  // 留出时间让线程B去锁住b
        	synchronized (DeadLock.a) {
        		System.out.println("B got a");
                sleep();
            }

        }	
	}
    // 让线程等待一段时间,以便使A,B都能先锁住一个资源
	private void sleep() {
		try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
	}

}


输出:
在这里插入图片描述
从输出结果可以看出,B没有得到a,A也没有得到b,程序陷入无限等待状态中。当破坏死锁后(注释掉其中一个进程),

public class DeadLock {
    public static Object a = new Object();
    public static Object b = new Object();
    
    public static void main(String[] args){
    	DeadLock d = new DeadLock();
    	d.setDeadlock();
    }    
    
    // 建立死锁
    private void setDeadlock() {
        Thread A = new Thread(new Runnable() {
            public void run() {
                threadA();
            }
        });
        A.start();
    }
    protected void threadA() {
    	synchronized (DeadLock.a) {
    		System.out.println("A keeps a");
            sleep();  // 留出时间让线程B去锁住b
        	synchronized (DeadLock.b) {
        		System.out.println("A got b");
                sleep();
            }

        }	
	}


	private void sleep() {
		try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
	}

}

输出为:
在这里插入图片描述
可以看到程序正常结束,A获取了b。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/StrongbyTime/article/details/86490421
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢