JDK source code parsing (JUC) lock – ReetrentLock in Java
JDK source code parsing (JUC) lock – Java lock ReetrentLock
The Lock interface
Before the Lock interface appeared, Java was the Lock function realized by synchronized keyword. After javase5, Lock interface was added in packets
Lock is used in much the same way as distributed locks are constructed.
Lock lock = new ReentrantLock
lock.lock();
try{}finally{
lock.unlock();
}
Copy the code
The Lock interface provides features that the Synchronized keyword does not
Try to acquire the lock without blocking | The current thread attempts to acquire the lock. If no other thread acquires the lock, it succeeds |
---|---|
Can be interrupted to obtain the lock | |
Timeout acquisition lock | The lock is acquired for the specified time |
Lock interface API
api | |
---|---|
void lock() | Lock Obtains the lock preferentially and responds to the interrupt only after the lock is successfully obtained. |
void lockInterruptibly() throws InterruptedException | LockInterruptibly prioritizes the response interrupt over the normal or reentrant acquisition of the response lock. |
|
Copy the code
| Boolean tryLock () | | | Boolean tryLock (long time, TimeUtil unit) throws InterruptedException | | | void unlock () | releases the lock | | Condition newCondition | get wait notification component, the component and the current lock binding, the current thread only for lock, to invoke the components of the wait () method, and after the call, the current thread will release the lock |
Queue synchronizer
Lock implementation based on queue synchronizer, AbstractQueuedSynchronized (hereinafter referred to as synchronizer), use a int member variable synchronous state, through the built-in FIFO queue to complete resources for thread line work
public class ReentrantLock implements Lock.java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. Here it is!! * /
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock(a);
/** * Performs non-fair tryLock. tryAcquire is * implemented in subclasses, But both need nonfair * try for trylock method
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// The main exception to the fair lock method is hasqueuedToraise
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true; }}else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
// Release the current lock
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if(Thread.currentThread() ! = getExclusiveOwnerThread())throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively(a) {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition(a) {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner(a) {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount(a) {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked(a) {
returngetState() ! =0;
}
/**
* Reconstitutes this lock instance from a stream.
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state}}/** * Sync object for non-fair locks */
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
Try immediate barge, backing up to normal * acquire on failure. ** */
final void lock(a) {
// If the current state is 0 then the current thread is set to the current thread, which means that it is unfair to acquire the lock directly
if (compareAndSetState(0.1))
setExclusiveOwnerThread(Thread.currentThread());
else
// Queue for lock
acquire(1);
}
// Queue for lock
protected final boolean tryAcquire(int acquires) {
returnnonfairTryAcquire(acquires); }}/** * Sync object for fair locks */
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// queue to get
// This method is called a fair lock
final void lock(a) {
acquire(1);
}
/** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
Hasqueuedtoraise records the platoon order, the first to obtain the lock first
/ / AbstractQueuedSynchronized maintains a Node queue
if(! hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true; }}else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false; }}Copy the code
ReetrentLock reentrant lock
Re-entry lock, which can support a thread to repeatedly lock resources, see the code above.
Read-write lock ReetrentReadWriteLock
features
Fair selection | |
---|---|
reenter | |
Lock down |
Interface sample
int getReadLockCount() | The number of times the lock was read |
---|---|
int getReadHoldCount() | The number of times the current thread may have read the lock |
int getWriteLockCount() | |
int getWriteHoldCount() |
The use of the Lock
Read/write locks are explained by Cache. HashMap is non-thread-safe, and Cache is thread-safe by read/write locks
public class Cache {
static Map<String,Object> map = new HashMap<String,Object>();
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
public static final Object get(String key){
r.lock();
try {
return map.get(key);
}finally{ r.unlock(); }}public static final Object put(String key,Object value){
w.lock();
try {
return map.put(key,value);
}finally{ w.unlock(); }}public static final void clear(a) {
w.lock();
try {
map.clear();
}finally{ w.unlock(); }}}Copy the code
Condition interface and examples
public class ConditionUseCase {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public static void main(String[] args){}public void conditionWait(a) throws InterruptedException {
lock.lock();
try {
condition.await();
}finally{ lock.unlock(); }}public void conditionSignal(a){
lock.lock();
try {
condition.signal();
}finally{ lock.unlock(); }}}Copy the code
Partial method description
void await() | The current thread enters the wait state until it is notified or interrupted |
---|---|
void awaitUninterruptibly() | The current thread enters the wait state and is not sensitive to interrupts |
long awaitNanos(long nanosTimeout) | The current thread enters the wait state until notified, interrupted, or timed out. The return value indicates the remaining time. If the return value is 0 or negative, the thread is considered timed out |
boolean awaitUntil(Date deadline) | The current thread enters the wait state until notified, interrupted, or at a specified time. Returns true if the specified time is not reached, false otherwise |
void signal() | Wakes up a thread waiting in condition that must acquire the lock associated with the condition before returning from the wait method |
void signlAll() | Wake up all threads in the waiting condition. Threads that can return from the waiting method must acquire the lock associated with the condition |
- BoundedQueue explains the Condition
public class BoundedQueue<T> {
private Object[] items;
private int addIndex,removeIndex,count;
private Lock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private Condition notFull = lock.newCondition();
public BoundedQueue(int size){
items = new Object[size];
}
public void add(T t) throws InterruptedException {
lock.lock();
try {
while(count == items.length)
notFull.await();
items[addIndex] = t;
if(++addIndex == items.length)
addIndex = 0;
++count;
notEmpty.signal();
}finally{ lock.unlock(); }}public T remove(a) throws InterruptedException {
lock.lock();
try {
while(count == 0)
notEmpty.await();
Object x = items[removeIndex];
if(++removeIndex == items.length)
removeIndex = 0;
--count;
notFull.signal();
return (T) x;
}finally{ lock.unlock(); }}}Copy the code