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