死锁

    前面说过使用同步机制可以解决多线程安全问题,不过使用同步也是有代价的,比如有如下两个缺点:1、效率低下;2、在有同步嵌套的时候容易出现死锁。那么什么是死锁呢?死锁就是指有两个或多个线程在相互争夺资源的过程中发生的一种相互等待的现象。

 

    java中发生死锁有如下四个必要条件:

        1、互斥使用,即当资源被一个线程占有时。别的线程不能使用;

        2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放;

        3、请求和保持,即当资源请求者在请求其他资源的同时保持对原有资源的占有;

        4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源。这样就形成了一个等待环路。

 

    当以上四个条件都成立时,便形成了死锁。下面分别用synchronizedLock锁模拟死锁产生的情况。

 

    创建一个锁对象类MyLock


package com.gk.thread.deadlock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyLock {
	
	// 使用synchronized修饰代码块的时候锁对象可以是任意的,这里使用字符串来代替
	public static String strLockA = new String();
	public static String strLockB = new String();
	
	public static final Lock lockA = new ReentrantLock();
	public static final Lock lockB = new ReentrantLock();

}


    synchronized实现:


package com.gk.thread.deadlock.synchronization;

import com.gk.thread.deadlock.MyLock;

public class DeadLock extends Thread {

	private boolean flag;	
	private String name;
	
	public DeadLock(String name, boolean flag) {
		this.name = name;
		this.flag = flag;
	}
	
	@Override
	public void run() {

		if(flag) {
			
			synchronized(MyLock.strLockA) {		// if行1
				
				System.out.println(name + "锁住strLockA...");	// if行2
				
				synchronized(MyLock.strLockB) {		// if行3
					
					System.out.println(name + "锁住strLockB...");		// if行4
				}
			}
			
		}else {
			
			synchronized(MyLock.strLockB) {		// else行1
				
				System.out.println(name + "锁住strLockB...");	// else行2
				
				synchronized(MyLock.strLockA) {		// else行3
					
					System.out.println(name + "锁住strLockA...");		// else行4
				}
			}
		}
		
	}

}


    测试代码:

package com.gk.thread.deadlock.synchronization;

public class Test {
	
	public static void main(String[] args) {
		
		// true执行DeadLock类run方法的if语句
		new DeadLock("线程A", true).start();
		
		// false执行DeadLock类run方法的else语句
		new DeadLock("线程B", false).start();
	}

}


    代码解析:

    DeadLock类的flag标记是用来人为控制不同线程执行不同路径,当flagtrue时执行if块,当flagfalse时执行else块。在测试代码中我们创建两个线程:线程A和线程B,并让线程Atrue执行if块,让线程Bfalse执行else块。在if中首先锁住strLockA,然后锁住strLockBelse正好相反。

 

    有这样一种情况:线程A进入了if块执行if1这条语句,然后strLockA就被线程A锁住了,此时正好线程B进入了else块执行了else1这条语句,然后strLockB就被线程B锁住了。当线程A要往下执行if3锁住strLockB的时候,发现strLockB已经被占用还没释放,此时,线程A就一直等待strLockB能够被释放以供自己使用;同理线程B要往下执行else3锁住strLockA的时候也发现strLockA被占用,也在等待strLockA能被释放。就这样两个线程都在等待其他线程能够释放自己所需资源而陷入了无限等待状态,从而就产生了死锁现象。


    注意看控制台输出的时候小方块一直是红色的,说明程序一直在运行着而不会结束。


    Lock锁实现:


package com.gk.thread.deadlock.lock;

import com.gk.thread.deadlock.MyLock;

public class DeadLock extends Thread{
	
	private String name;
	private boolean flag;

	
	public DeadLock(String name, boolean flag) {
	
		this.name = name;
		this.flag = flag;
	}
	
	@Override
	public void run() {

		if(flag) {			///   if
			
			MyLock.lockA.lock();
			try {
				System.out.println(name + "锁住了lockA...");
				
			}catch (Exception e) {
				/*
				 * 在catch块中释放锁,
				 * 如果没有异常或异常不匹配导致catch块不能执行,
				 * 从而导致锁不能及时释放
				 */
				MyLock.lockA.unlock();	
				System.out.println(name + "释放了lockA...");
			}
			
			
			/
			MyLock.lockB.lock();
			try {
				System.out.println(name + "锁住了lockB...");
				
			}catch (Exception e) {
				MyLock.lockB.unlock();
				System.out.println(name + "释放了lockB...");
			}
			
		}else {			///   else
			
			MyLock.lockB.lock();
			try {
				System.out.println(name + "锁住了lockB...");
				
			}catch (Exception e) {
				MyLock.lockB.unlock();	
				System.out.println(name + "释放了lockB...");
			}
			
			
			/
			MyLock.lockA.lock();
			try {
				System.out.println(name + "锁住了lockA...");
				
			}catch (Exception e) {
				MyLock.lockA.unlock();
				System.out.println(name + "释放了lockA...");
			}
		}
		
	}

}


    测试代码:


package com.gk.thread.deadlock.lock;

public class Test {
	
	public static void main(String[] args) {
		
		// lock锁测试
		new DeadLock("线程A", true).start();
		new DeadLock("线程B", false).start();
	}

}


       代码解析:

    相信认真看了上面对synchronized代码解析的,对Lock的理解应该不难。一般认为Lock出现死锁的原因是因为代码不规范引起的,比如上面代码中释放锁的代码lock.unlock()不应该放在catch块,而应该放在finally块中确保锁能被及时的释放。


 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值