可重入锁 ReentrantLock

推荐 : ReentrantLock与synchronized

1. 什么是可重入锁?

   - “就是可以重新获得锁!”可重入的意思是线程可以重复获得它已经持有的锁。Java的synchronized块是可重入的。

  看下面代码 :

public class Reentrant{
	public synchronized outer(){
		inner();
	}
	public synchronized inner(){
		//do something
	}
}

 2. ReentrantLock and synchronized的不同:

     - ReentrantLock 必须显示的加锁lock(),最后必须记得unlock() 而 synchronize是内置锁,不需要显示的释放锁

     - ReetrantLock 可以响应中断,可以保证在线程还未获得并且试图获得锁时如果发现线程中断,则抛出异常清除中断标记退出竞争。通过“lockInterruptibly()    

     - 而synchronize不会响应中断!多线程竞争一个锁时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。即使你调用了interrupt也是没用的!

     - 公平性,ReentrantLock 的构造方法可以设置一个boolean fair ,获得锁的顺序是不是和申请锁的时间的顺序是一致的 ,不允许插队,默认不公平的!

  

4. lock方法

  

/**public void lock() 
获取锁。 
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。 
如果当前线程已经保持该锁,则将保持计数加 1(state),并且该方法立即返回。 
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。 
*/  

 5. 可重入显示锁的简单实现

   

public class Lock{
	boolean isLocked = false;
	Thread  lockedBy = null;
	int lockedCount = 0;

	public synchronized void lock()
		throws InterruptedException{
		Thread callingThread =
			Thread.currentThread();
		while(isLocked && lockedBy != callingThread){
			wait();
		}
		isLocked = true;
		lockedCount++;
		lockedBy = callingThread;
  }

	public synchronized void unlock(){
		if(Thread.curentThread() ==
			this.lockedBy){
			lockedCount--;

			if(lockedCount == 0){
				isLocked = false;
				notify();
			}
		}
	}

	...
}

 6. 原理分析 :

    ReentrantLock的实现依赖于java同步器框架AbstractQueuedSynchronizer(本文简称之为AQS)。AQS使用一个整型的volatile变量(命名为state)来维护同步状态,马上我们会看到,这个volatile变量是ReentrantLock内存语义实现的关键。 下面是ReentrantLock的类图(仅画出与本文相关的部分):

 

猜你喜欢

转载自kainever7.iteye.com/blog/2202042