Java中如何理解可重入锁的概念?为什么ReentrantLock不手动释放锁会造成死锁?

之前有文章说过,synchronized和ReenTrantLock都是可重入锁,那么什么是可重入锁?

可重入锁从字面意思就比较容易理解,自己获取了锁以后,可以再次获取该锁(重入)就叫可重入锁,同一个线程每次获取锁,锁计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

我们就以之前卖票的例子进行讲解,因为synchronized加锁和解锁的过程是自动进行,所以不会造成死锁,而ReentrantLock加锁和解锁的过程需要手动,所以如果加锁和释放锁次数不一,会导致死锁,我们看代码:

public class FairLocked implements Runnable {
	private int seatNumber = 100;
	/**
	 * 公平锁实现 ReentrantLock构造方法中设置为true:代表公平锁
	 * 
	 * 设置为false:代表非公平锁 默认也是非公平锁
	 * 
	 */
	/** private ReentrantLock lock = new ReentrantLock(true); */

	/** private ReentrantLock lock = new ReentrantLock(false); */
	private ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
			try {
				lock.lock();
				if (seatNumber > 0) {
					Thread.sleep(100);
					--seatNumber;
					System.out.println(Thread.currentThread().getName() + "占用1个座位,还剩余 " + seatNumber + "个座位");
				} else {
					System.out.println(Thread.currentThread().getName() + ":不好意思,票卖完了!");
					break;
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {

				/** lock.unlock(); */
			}
		}
	}

	public static void main(String[] args) {
		FairLocked rlbr = new FairLocked();
		Thread t1 = new Thread(rlbr, "A窗口");
		Thread t2 = new Thread(rlbr, "B窗口");
		t1.start();
		t2.start();
	}
}

那么,可重入锁的原理是什么呢?

之前我们也有提到过一个词,叫锁计数器。重入锁实现机制就是基于一个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的线程持有者,同时将锁计数器置为1;此时其它线程请求该锁,就只能等待,而该锁持有者却可以再次请求锁,同时锁计数器会递增,当线程退出同步代码块时,计数器会递减,直至锁计数器为0,则释放。

所以,如果ReentrantLock不手动释放锁,就会造成死锁。

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