ロックのJUC、ReentrantLockの排他ロックリエントラント

序文

  再入国ロック、ロックにReentrantLockのと実現Serializableインタフェース

  ReentrantLockのJava環境でリエントラントロックが同期されています

  ロック申し出2コンストラクタReentrantLockの:公正かつ不当なロックロック(デフォルト)を作成

  • 3つの内部クラスReentrantLockの同期、NonfairSyncとFairSyncクラスがあります。
  • 同期抽象クラスを継承AbstractQueuedSynchronized
  • NonfairSync(非アームロック)Syncは、抽象クラスを継承しています。
  • FairSync(フェアロックは)同期抽象クラスを継承しています。

  フェアロック、ロックを発行するための取得要求内のスレッド;不公平ロック、中断を許可します。

  別のスレッドがロックを保持しているか、キュー内で待機しているロックを待っている他のスレッドが、新しい問題は、クラスのスレッドに置かれる要求した場合フェアがロックされました。

  不当なロック性能より公正ロックパフォーマンスの原因

  • 実際に中断されたスレッドに回復して実行スレッド間の深刻な遅延があり
  • ロック要求とスレッドB.、スレッドがロックを保持していると仮定 ロックがAによって保持されているので、Bは、このように中断されるであろう。ロックが解除された場合、A、Bが再びロックを取得しようとしますので、Bは、目覚めされます。これと同時に、スレッドCはまた、ロックを要求している場合、Cは、おそらく得られる前にBにある完全に覚醒している、使用、およびロックを解除します。これは、常にロックBが延期されていない取得し、Cが先にロックを獲得し、そして、お互いに有利な状況でスループットをもさ向上します

  ロックは長いロックを要求している比較的長い時間や平均時間間隔を保持されている場合は、ロックが使用され、公正でなければなりません

スレッド切り替えの多くを犠牲にしてFIFO原理に従ってロックへの公平なアクセスを確保するためのロック。非フェアロックはスレッド「飢餓」になりますが、まれにその大きなスループットを確保するためにスイッチを通すかもしれないが。

ソース

ReentrantLockののクラスはの実装であるロックインターフェース、界面での初見どこ抽象メソッド

ロックAPI

ロック(); //ロック取得
 のボイド lockInterruptibly()がスロー例外:InterruptedExceptionを、現在のスレッドが中断された場合、//、そしてロックの取得
 ブールのtryLock();場合にのみ、アイドル状態でロック//ロックを取得します。
ブールのtryLock(ロングタイム、TimeUnitでユニット)がスロー任意の時点で//ロックアイドル、および現在のスレッドがロック中断され、取得されていない。例外:InterruptedExceptionを
 無効UNLOCK(); //ロック解除
条件newConditionを(); //戻りネクタイ新しい条件のインスタンス与えられた、このインスタンスをロックします。

 

 条件ロックinterfaceインターフェイス、どのような効果がある表示されますか?

調子

  待機()、通知()と同期して、条件やロックも通知のために同じ待ち時間で達成することができるとの通知を待つを達成することができますが、両者の違いがあります

条件は2種類の方法、現在のスレッドのコールこれらの方法に通知/待機を定義するには、事前に取得する必要があるロックに関連する状態、オブジェクトの状態オブジェクトはオブジェクトによって作成される(Lock.newCondition)をロックアウト、換言すれば、条件に依存していますロックオブジェクト。

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

おすすめ

転載: www.cnblogs.com/FondWang/p/12112234.html