Do you really understand ReentrantLock yet?

is synchronized to the JVM hosting executed, Lock locking is achieved through code. Therefore Lock more flexible and to be easy for developers to operate according to the appropriate scene, Lock is an interface needs to implement it for use, ReetrantLock main implementation class Lock's, ReetrantLock is a reentrant lock, and can specify a fair lock and unfair lock, we have to look at his specific implementations.

A, ReentrantLock use

        ReentrantLock lock = new ReentrantLock();
		//如果被其它线程占用锁,会阻塞在此等待锁释放
		lock.lock();
		try {
			//操作
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//释放锁
			lock.unlock();  
		}
复制代码

The above is only one embodiment, can be seen to use a relatively simple ReentrantLock, ReentrantLock create an object, lock by lock () method, using the unlock () method releases the lock operation.

He's locked in three ways, using the lock, trylock, trylock (long, TimeUnit) specified time parameters. Use the lock to get the lock, and if the lock is held by another thread, it will be in a wait state. In addition we need to take the initiative to call the unlock method to release the lock, even if an exception occurs, he will not take the initiative to release the lock, we need to explicitly release. Trylock acquire a lock using the method, there is a return value, get returns true if successful, failure to obtain returns false, would not have been in a wait state. Use trylock (long, TimeUnit) parameters specify the time to acquire a lock, the lock is acquired returns true, false returns a timeout within the waiting time. You can also call lockInterruptibly way to break a lock, if the thread is waiting to acquire locks, can interrupt waiting state of the thread.

Second, what is reentrant lock

ReentrantLock we said above is a reentrant lock, then, what is reentrant lock it? Reentrant lock means, the thread lock may be repeated on the same lock, but not blocked, so that the deadlock can be avoided. Let's look at the validation code reentrant lock:

public static class TestReentrantLock {
	private Lock lock = new ReentrantLock();
	public void method() {
		lock.lock();
		try {
			System.out.println("方法1获得ReentrantLock锁");
			method2();
		} finally {
			lock.unlock();
		}
	}
	public void method2() {
		lock.lock();
		try {
			System.out.println("方法2重入ReentrantLock锁");
		} finally {
			lock.unlock();
		}
	}
	public static void main(String[] args) {
			new TestReentrantLock().method();
	}
}
复制代码

We can see that by the above code, ReentrantLock having the reentrancy. So, what this reentrant underlying implementation is it?

Reentrant lock the underlying implementation

ReentrantLock AQS is a value used in the state, the thread can be kept to increase the value of the lock state, the corresponding need to unlock to unlock until the zero state. And the value of state is modified with volatile, the following is a source code implementation specific.

 //java.util.concurrent.locks.ReentrantLock.FairSync
 protected final boolean tryAcquire(int acquires) {
 	//获取当前线程
    final Thread current = Thread.currentThread();
    int c = getState();
    //当前锁没被占用
    if (c == 0) {
        //1.判断同步队列中是否有节点在等待
 	   if (!hasQueuedPredecessors() &&
 		   compareAndSetState(0, acquires)) {//2.如果上面!1成立,修改state值(表明当前锁已被占用)
            //3.如果2成立,修改当前占用锁的线程为当前线程
 		   setExclusiveOwnerThread(current);
 		   return true;
 	   }
    }
    //占用锁线程==当前线程(重入)
    else if (current == getExclusiveOwnerThread()) {
 	   int nextc = c + acquires;//
 	   if (nextc < 0)
 		   throw new Error("Maximum lock count exceeded");
        //修改status
 	   setState(nextc);
 	   return true;
    }
    //直接获取锁失败
    return false;
}

复制代码

Third, what is fair locks

We said earlier ReentrantLock can achieve fair and unfair lock lock, then what is fair locks? What is a non-locking it fair? When the so-called fair locks, that is, multiple threads request to acquire the same resources, to ensure the thread requests in the order, followed by the implementation, to ensure fair competition results. Conversely, unfair lock is not in accordance with the order request thread, each thread lock together to compete, who grabbed who yes.

We said above fair ReentrantLock lock is achieved through inheritance AQS, we look at his specific implementation.

AQS

AQS is an abstract class, mainly used by way of inheritance. AQS function is divided into two types: shared and exclusive. AQS implementation relies on internal synchronous queue, which is bi-directional FIFO queue, if the current thread lock contention fails, then the current thread and AQS will wait state information is configured to sync a Node added to the queue, and then blocked the thread. When a thread releases the lock acquired lock, it will wake up a blocked node (thread) from the queue. AQS member using an int type synchronous state variable state is represented, when the state> 0 indicates when the lock has been acquired, state = 0 when the lock is released when expressed.

When there is lock contention, when a new thread to join, this thread will be added to the node Node encapsulated into sync queue and the front pointer points to a node of the new thread, the rear pointer on a node point to the new node thread. This is done by modifying the pointer to CAS.

The head node when the lock is released, it will wake up the subsequent node, if successful successor node to acquire the lock, put myself to the first node, the head node does not need to set up with CAS, because the setting is done by the head node to acquire a lock thread , and the synchronization lock can only be obtained by a thread, so no guarantee CAS.

Fair lock Source

Was added synchronous queue (queue is empty when the synchronization will directly get the lock), waiting for a lock

//java.util.concurrent.locks.ReentrantLock.FairSync
final void lock() {
	acquire(1);
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquire(int arg) {
	if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
		selfInterrupt();
}

复制代码

tryAcquire (): template method acquire locks

//java.util.concurrent.locks.AbstractQueuedSynchronizer
//1
private Node addWaiter(Node mode) {
 //生成node
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
 	//将node加到队列尾部
 	   node.prev = pred;
 	   if (compareAndSetTail(pred, node)) {
 		   pred.next = node;
 		   return node;
 	   }
    }
    //如果加入失败(多线程竞争或者tail指针为null)
    enq(node);
    return node;
}
//1.1  
private Node enq(final Node node) {
 //死循环加入节点(cas会失败)
    for (;;) {
 	   Node t = tail;
 	   if (t == null) { //tail为null,同步队列初始化
 		//设置head指针
 		   if (compareAndSetHead(new Node()))//注意这里是个空节点!!
 			   tail = head;//将tail也指向head
 	   } else {
 		   node.prev = t;//将当前node加到队尾
 		   if (compareAndSetTail(t, node)) {
 			   t.next = node;
 			   return t;//注意这里才返回
 		   }
 	   }
    }
}
//2
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
 	//表示是否被打断
 	   boolean interrupted = false;
 	   for (;;) {
 		//获取node.pre节点
 		   final Node p = node.predecessor();
 		   if (p == head //当前节点是否是同步队列中的第二个节点
 		   && tryAcquire(arg)) {//获取锁,head指向当前节点
 			   setHead(node);//head=head.next
 			   p.next = null;//置空 
 			   failed = false;
 			   return interrupted;
 		   }

 		   if (shouldParkAfterFailedAcquire(p, node) && //是否空转(因为空转唤醒是个耗时操作,进入空转前判断pre节点状态.如果pre节点即将释放锁,则不进入空转)
 			   parkAndCheckInterrupt())//利用unsafe.park()进行空转(阻塞)
 			   interrupted = true;//如果Thread.interrupt()被调用,(不会真的被打断,会继续循环空转直到获取到锁)
 	   }
    } finally {
 	   if (failed)//tryAcquire()过程出现异常导致获取锁失败,则移除当前节点
 		   cancelAcquire(node);
    }
}

复制代码

acquireQueued (addWaiter (Node.EXCLUSIVE), arg): Add the synchronous queue

//java.util.concurrent.locks.AbstractQueuedSynchronizer
//1
private Node addWaiter(Node mode) {
 //生成node
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
 	//将node加到队列尾部
 	   node.prev = pred;
 	   if (compareAndSetTail(pred, node)) {
 		   pred.next = node;
 		   return node;
 	   }
    }
    //如果加入失败(多线程竞争或者tail指针为null)
    enq(node);
    return node;
}
//1.1  
private Node enq(final Node node) {
 //死循环加入节点(cas会失败)
    for (;;) {
 	   Node t = tail;
 	   if (t == null) { //tail为null,同步队列初始化
 		//设置head指针
 		   if (compareAndSetHead(new Node()))//注意这里是个空节点!!
 			   tail = head;//将tail也指向head
 	   } else {
 		   node.prev = t;//将当前node加到队尾
 		   if (compareAndSetTail(t, node)) {
 			   t.next = node;
 			   return t;//注意这里才返回
 		   }
 	   }
    }
}
//2
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
 	//表示是否被打断
 	   boolean interrupted = false;
 	   for (;;) {
 		//获取node.pre节点
 		   final Node p = node.predecessor();
 		   if (p == head //当前节点是否是同步队列中的第二个节点
 		   && tryAcquire(arg)) {//获取锁,head指向当前节点
 			   setHead(node);//head=head.next
 			   p.next = null;//置空 
 			   failed = false;
 			   return interrupted;
 		   }

 		   if (shouldParkAfterFailedAcquire(p, node) && //是否空转(因为空转唤醒是个耗时操作,进入空转前判断pre节点状态.如果pre节点即将释放锁,则不进入空转)
 			   parkAndCheckInterrupt())//利用unsafe.park()进行空转(阻塞)
 			   interrupted = true;//如果Thread.interrupt()被调用,(不会真的被打断,会继续循环空转直到获取到锁)
 	   }
    } finally {
 	   if (failed)//tryAcquire()过程出现异常导致获取锁失败,则移除当前节点
 		   cancelAcquire(node);
    }
}

复制代码

selfInterrupt (): wake up the current thread

static void selfInterrupt() {//在获取锁之后 响应intterpt()请求
	Thread.currentThread().interrupt();
}

复制代码

These are interpreted ReadWriteLock principle and source of hope that we can have a harvest.

Part Reference: juejin.im/post/5ae1b4...

Guess you like

Origin juejin.im/post/5d50cdbdf265da03f333453a