JUC of Lock, ReentrantLock exclusive lock reentrant

Foreword

  ReentrantLock to re-entry lock, Lock and realized Serializable interface

  In ReentrantLock java environment and are reentrant lock Synchronized

  Lock offers two constructor ReentrantLock: create fair and unfair lock lock (default)

  • There are three internal classes ReentrantLock Sync, NonfairSync and FairSync classes.
  • Sync abstract class inherits AbstractQueuedSynchronized
  • NonfairSync (non-arm lock) Sync inherited abstract class.
  • FairSync (fair Lock) inherited Sync abstract class.

  Fair lock, a thread in the order acquisition request issued lock; unfair locks, allow interruption.

  Fair locked if another thread holding the lock or other threads waiting for the lock in the waiting queue, then request a new issue will be put to the thread of class.

  Unfair locking performance than the cause of fair-locking performance

  • There is a serious delay between the thread actually run with the recovery in a suspended thread
  • Suppose A thread holds a lock, the lock request and the thread B. Since the lock is held by A, B will thus be suspended. When the lock is released A, B will be awakened, so B will attempt to acquire the lock again. At the same time, if the thread C is also requesting the lock, then C is likely to be obtained prior to B is fully awake, use, and release the lock. This is a win-win situation, always get the lock B is not postponed, C earlier won the locks, and the throughput is also improving the.

  When the lock is held relatively long time or average time interval is longer requesting the lock, the lock should be used fair

Lock to ensure fair access to the lock according to the FIFO principle at the expense of a lot of thread switching. Although non-fair lock may result in the thread "hunger", but rarely thread switch to ensure its greater throughput.

Source

ReentrantLock class is an implementation of the Lock interface, a first look at the interface where the abstract methods

Lock API

void Lock (); // acquiring the lock
 void lockInterruptibly () throws InterruptedException; // if the current thread is interrupted, then acquire the lock
 boolean tryLock (); // to acquire the lock when the lock only in idle state.
boolean tryLock ( Long Time, TimeUnit Unit) throws InterruptedException; // lock idle at any given time, and the current thread has not been interrupted acquire the lock
 void UNLOCK (); // release the lock 
Condition newCondition (); // return tie Lock this instance given a new Condition instance.

 

 Condition Lock interface appears interface, which is what effect?

Condition

  wait (), notify () and wait for notification can be achieved with synchronized, Condition and Lock can also be achieved with the same wait for notification, but there are differences between the two

Condition defines the wait / notify two types of methods, the current thread call these methods, it is necessary to obtain in advance to lock objects associated Condition, Condition objects are created by objects Lock out (Lock.newCondition) , in other words, it is dependent on Condition Lock object.

ConditionAPI

public interface Condition {
    void await() throws InterruptedException;  //当前线程进入等待状态直到被通知(signal)或被中断
    void awaitUninterruptibly();  //不响应中断等待,直到被通知(signal)
    long awaitNanos(long nanosTimeout) throws InterruptedException;  //等待指定时长直到被通知或中断或超时
    boolean await(long time, TimeUnit unit) throws InterruptedException;  //同上
    boolean awaitUntil(Date deadline) throws InterruptedException; //当前线程进入等待状态直到被通知、中断或者到某个事件。若没有到指定事件就被通知,方法返回true,否则false。
    void signal();  //唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关联的锁。
    void signalAll();  //唤醒所有等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关的锁
}

 

ReentrantLock源码

构造器

public ReentrantLock() {sync = new NonfairSync();}  //默认使用非公平锁对象
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}  //根据参数,判断使用 非公平/公平 锁。

 

 

 

内部类

  构造器中,是创建内部类的对象NonfairSync(非公平锁)和FairSync(公平锁),它们都实现了Sync静态内部类

  Sync静态内部类源码

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;
        abstract void lock();
     //非公平锁获取锁 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //当前线程 int c = getState(); //同步状态 if (c == 0) { //如果为0,当前锁未被其他线程获取 if (compareAndSetState(0, acquires)) { //通过CAS设置 setExclusiveOwnerThread(current); //设置获取锁的此线程 return true; } } else if (current == getExclusiveOwnerThread()) { //如果锁状态不为0,则已经被其他线程获取。如果是当前线程,也就是同一个线程再次获取这个锁,即可重入 int nextc = c + acquires; //状态值增加。 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); //设置状态值 return true; } return false; }      //释放锁 protected final boolean tryRelease(int releases) { int c = getState() - releases; //获取状态 if (Thread.currentThread() != getExclusiveOwnerThread()) //当前线程如果不是该锁的线程,抛异常 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //状态值为0,释放锁 free = true; setExclusiveOwnerThread(null); } setState(c); return free; }      //检查锁是否为此线程的所有者。就是之前是否是这个线程获取的锁 protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); }      //创建ConditionObject对象 final ConditionObject newCondition() { return new ConditionObject(); }      //返回该锁的线程 final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); }      //返回锁的状态值。如果是该锁的线程,返回对应的值;不是返回0 final int getHoldCount() { return isHeldExclusively() ? getState() : 0; }      //判断是否已被其他线程获取,是否已经锁住 final boolean isLocked() { return getState() != 0; } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }

 

 

 

NonfairSync非公平锁的源码实现

  非公平锁就是一种获取锁的抢占机制,是 随机获得锁 的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的了.

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
     //执行锁 final void lock() { if (compareAndSetState(0, 1)) //通过CAS操作,设置状态值 setExclusiveOwnerThread(Thread.currentThread()); //设置该锁的线程 else acquire(1); }
     //尝试获取锁。默认是非公平锁,转至Sync中的方法
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }

 

FairSync公平锁的源码实现

  公平锁表示线程获取锁顺序是按照 线程加锁的顺序 来分配的,即先来先得的 FIFO 先进先出顺序。

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
     //执行加锁
final void lock() { acquire(1); }
     //尝试获取锁 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); //当前线程 int c = getState(); //状态值 if (c == 0) { //等于0,该锁未被线程获取 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { //hasQueuedPredecessors()方法判断头节点是否为当前线程 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { //如果不等于0,判断该锁的线程是否为当前线程,是可重入。 int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }

 

 

 

方法

//获得锁
public void lock() {
    sync.lock();
}
//当前线程未被中断,获取锁 public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } //该锁未被其他线程获取,则当前线程获取锁。默认非公平锁 public boolean tryLock() { return sync.nonfairTryAcquire(1); } //给定时间内,该锁未被其他线程获取,该线程未被中断,可获取锁 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } //释放锁 public void unlock() { sync.release(1); } //返回Condition对象 public Condition newCondition() { return sync.newCondition(); } //返回同步状态 public int getHoldCount() { return sync.getHoldCount(); } //锁的持有者是否为当前线程 public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } //该锁是否已被线程获取 public boolean isLocked() { return sync.isLocked(); } //判断是否为公平锁 public final boolean isFair() { return sync instanceof FairSync; } //返回拥有该锁的线程 protected Thread getOwner() { return sync.getOwner(); } //查询是否有线程正在等待获取此锁 public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); //这个方法就是判断 头节点==尾结点? 没有等待线程:有等待线程 } //判断线程是否在等待线程队列中 public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } //返回等待线程数 public final int getQueueLength() { return sync.getQueueLength(); } //返回线程队列 protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } //查询是否有线程正在等待与此锁关联的给定条件。 public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } //返回与此锁关联的给定条件下等待的线程数的估计值。 public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } //返回一个集合,其中包含可能正在等待与此锁关联的给定条件的线程。 protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); }

 

总结

  • ReentrantLock 提供了内置锁(synchronized)类似的功能和内存语义。
  • ReentrantLock 提供了包括定时的锁等待、可中断的锁等待、公平性以及实现非块结构的加锁。
  • Condition 对线程的等待和唤醒等操作更加灵活,一个 ReentrantLock 可以有多个 Condition 实例,更有扩展性。
  • ReentrantLock 需要显示的获取锁,并在 finally 中释放锁。
  • JDK 1.8 以前 ReentrantLock 在性能上似乎优于 synchronized,但获取锁的操作不能与特定的栈帧关联起来,而内置锁可以。
  • 因为内置锁时 JVM 的内置属性,所以未来更可能提升 synchronized 而不是 ReentrantLock 的性能。
    • 例如对线程封闭的锁对象消除优化,通过增加锁粒度来消除内置锁的同步。
参考:https://www.jianshu.com/p/54e90999ee47

Guess you like

Origin www.cnblogs.com/FondWang/p/12112234.html