Java多线程深入理解学习笔记之六-----多线程同步Lock锁的使用及死锁问题

JDK5Lock锁的使用

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁在哪里释放了锁,为了更清晰的表达如何加锁释放锁,JDK5以后提供了一个新的锁对象Lock

Lock

void lock()

void unlock()

实现类:ReentrantLock

  使用Lock需要显式的加锁和解锁

  • 解锁操作需要放在finally块里,若不放在finally块中,若上面的代码抛出异常,那么会造成锁无法释放,可能会造成死锁问题
  • 另外,获取锁的操作不能放在try块里,因为Lock是可重入锁(上一篇博客已经讲述了可重入锁和不可重入锁的问题),如果外层也已经调用lock()方法,而里层因为调用lock()抛出异常然后调用unlock,外层无法知晓,导致外层代码无法正确同步

还是拿卖电影票的列子来说一下Lock锁的使用,代码如下:

自定义线程类:

package m8d8;

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

public class SellTickets implements Runnable{
	private int amount = 100;
	Lock lock = new ReentrantLock();
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			//加锁
            lock.lock();
			try {		
				if(amount>0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在出售第"+(amount--)+"张票");
				}
			}finally {
				//释放锁
				lock.unlock();
			}
		}
	}

}

 测试类:

package m8d8;

public class SellTicketsDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SellTickets sellTickets = new SellTickets();
		
		
		Thread threadA = new Thread(sellTickets, "窗口A");
		Thread threadB = new Thread(sellTickets, "窗口B");
		Thread threadC = new Thread(sellTickets, "窗口C");
		
		threadA.start();
		threadB.start();
		threadC.start();
		
	}

}

死锁问题

同步弊端

效率低

如果出现了同步嵌套,就容易产生死锁问题

死锁问题及其代码

是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

同步代码块的嵌套案例

下面是同步代码块嵌套造成死锁问题的案例:

自定义线程类:

package m8d9;

public class TextDemo extends Thread{
	private boolean isLock = false;
	
	private static  final  Object objA = new Object();
	private static final Object objB = new Object();
	
	public TextDemo(){
		
	}
	
	public TextDemo(boolean isLock) {
		this.isLock = isLock;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		if(isLock) {
			synchronized (objA) {
				System.out.println("if objA");
				synchronized (objB) {
					System.out.println("if objB");
				}
			}	
		}else {
			synchronized (objB) {
				System.out.println("else objB");
				synchronized (objA) {
					System.out.println("else objA");
				}
			}
		}
	}
	
	
}

 测试类:

package m8d9;

public class Demo {
	public static void main(String[] args) {
		TextDemo demo = new TextDemo(false);
		TextDemo demo2 = new TextDemo(true);
		
		demo.start();
		demo2.start();
	}
}

运行结果:

 分析:当demo2抢到线程的执行权的时候,执行输出:if objA(这时候还没有释放锁A),之后demo抢到了执行权执行了else objB(这时候还没有释放锁B),假设之后是demo线程抢到执行权,他在等锁A的释放才能继续执行,所以只能等待,但是的demo2也在等待锁B的释放继续执行,这就变成两个线程互相等待,造成了死锁问题

猜你喜欢

转载自blog.csdn.net/acDream_/article/details/81514161