Java synchronization mechanism -ReentrantLock use

basic concepts

ReentrantLock is from one row to start JDK1.5 introduced his locks, it provides more flexibility than the synchronized characteristics can be inherited, there are ways you can, you can have a variety of class variables. We look at how ReentrantLock use the following code:

public class ReentrantLockDemo {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        // 申请锁
        lock.lock();
        try {
            // 在此对共享数据进行访问
            // ...
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 总是在finally块中释放锁,以避免锁泄露
            lock.unlock();
        }
    }
}

As can be seen from the above code, it was quite simple, here to note that the best place is to release the lock finally block, so as not to cause the abnormal release of the lock did not succeed, resulting in lock leak.

Common method

method Explanation
lock() Acquire a lock
lockInterruptibly If the current thread is interrupted, then acquire the lock
tryLock Attempt to acquire the lock, no other threads are competing to acquire the lock and returns true, false otherwise immediately
unlock Release the lock
newCondition Returns a new Condition instance is bound to this Lock instance

CASE

CAS name is Compare and Swap, compare and swap i.e., synchronization is achieved by a multi-thread atomic instruction. Before it modifies the data in memory to start reading the actual value, the value of it as expected, when the real to modify the time, would be more then the actual value of the memory is consistent with the expected value just read, if consistent with the success can be modified, if not, the modification fails (explained in other threads during the modification has been modified).
The following figure shows that no other thread operations with a memory value during operation:
Here Insert Picture Description
The following figure shows the other thread operations with a memory value during the operation:
Here Insert Picture Description

AQS

AQS (AbstractQueuedSynchronizer) queue synchronizer i.e., the base frame is constructed which locks or other synchronization component, which is the core JUC and contracting the base component. AQS mainly includes the following:

  • State variable state: AQS by an integer value to identify the lock has not been occupied.
  • Synchronization Queue: internal synchronization queue AQS maintains a linked list structure, when the competition thread lock fails, it will be placed in the synchronization queue.
  • Condition queues: queue waiting is for implementing / notification (similar to the synchronized wait / notify).

Synchronous queue operating principle

Here Insert Picture Description

  • When only one execution thread, the thread is packaged Node, to acquire the lock and inserted into the list for execution of the head.
  • Multiple threads simultaneously competing lock, the lock is not acquired, were packed into a node, and in turn inserted into the blocked end of the queue.
  • Execution thread currently owns the lock after the lock is released, and wake up a thread behind it, was re-awakened thread lock contention, after obtaining the execution, after the implementation of a similar, but also wake up one thread releases the lock and back.

Condition queue operating principle

Here Insert Picture Description

  • When the thread holding the lock, so that the method calls Condition.await thread enters a wait state, it is first inserted into the corresponding queue Condition (Condition-way linked list queue is).
  • Condition inserted into the queue it will release the current lock, and wake up after blocking a thread queue, it removes itself from blocking the queue.
  • If the call Condition.signal method, it will wake up a thread waiting on the Condition of being awakened thread will be inserted into the tail of the queue blockage, and remove conditions from the queue.

ReentrantLock internal principle

We look ReentrantLock tracking the source code, enter it lock method:

  // ReentrantLock.lock()
  public void lock() {
  	  // 这个sync,是我们new ReentrantLock()时初始化的
      sync.lock();
  }

  //  无参构造函数
  public ReentrantLock() {
  	  // 默认初始化一个非公平锁
      sync = new NonfairSync();
  }

Here we first introduce fair and unfair lock lock.

Fair locks

Fair lock means that all the threads of the lock request in the order performed sequentially (e.g.: When a new thread request, there are found other threads blocking queue queues, it is inserted directly into the tail queue blocking queue).
When we create ReentrantLock objects, passing a true argument is created it is fair locks:

ReentrantLock lock = new ReentrantLock(true);

Unfair lock

Unfair lock is to have any new threads attempt to acquire the lock, there is a great chance to get directly to the locks (for example: a new thread request, regardless of its block list have no other thread in the queue, to compete directly lock, If the competition is on the successful direct execution).

ReentrantLock When creating a new, default is unfair lock, lock us into unfair NonfairSync code:

  static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        // 获取锁方法
        final void lock() {
            if (compareAndSetState(0, 1))
                // 获取到了锁设置一下当前线程是自身
                setExclusiveOwnerThread(Thread.currentThread());
            else
            	// 获取锁失败,则进入阻塞队列
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

Enter compareAndSetState method:

  protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

We said before, AQS is a state by an integer value (default is 0) to identify the lock has not been occupied, here is the way by CAS, the state from 0 to 1, if the modification is successful explained successfully acquired lock, If the modification fails explanation failed to acquire the lock. Modification failed to enter the acquire method:

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
        	// 加入阻塞队列
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

As can be seen, not to compete after the lock, it will be added to the blocking queue. We do not get to the bottom of the back side.

Released nine original articles · won praise 3 · Views 2424

Guess you like

Origin blog.csdn.net/ym572170/article/details/104802663