このブログシリーズをまとめ並行プログラミングを記録するプロセスを学ぶことです。私は簡単にアクセスできるように一緒にカタログペースト(ポータル)を置くように、時間によって書かれたより多くの記事としては、比較的緩いです。
ロックインターフェイスの概要
以下JUCパッケージ内のjava.util.concurrent.locks
同期メカニズムの伝統的なsynchronizd、待機のロックをベースのツールの範囲を提供し、補完のように通知し、強化パッケージ。ここではロック・インターフェースで開始します。
Lock
などのインターフェースを見ることができるsynchronized
強化されたバージョンは、より柔軟な機能を提供します。インタフェースはまた、制限ロック待ちを提供して、割り込みのロックや機能をロックしてみてください。次のようにインターフェースが定義されます。synchronized
Lock
public interface Lock {
// 尝试去获得锁
// 如果锁不可用,当前线程会变得不可用,直到获得锁为止。(中途会忽略中断)
void lock();
// 尝试去获取锁,如果锁获取不到,线程将不可用
// 知道获取锁,或者被其他线程中断
// 线程在获取锁操作中,被其他线程中断,则会抛出InterruptedException异常,并且将中断标识清除。
void lockInterruptibly() throws InterruptedException;
// 锁空闲时返回true,锁不空闲是返回false
boolean tryLock();
// 在unit时间内成功获取锁,返回true
// 在unit时间内未成功获取锁,返回false
// 如果当前线程在获取锁操作中,被其他线程中断,则会抛出InterruptedException异常,并且将中断标识清除。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
// 获取一个绑定到当前Lock对象的Condition对象
// 获取Condition对象的前提是当前线程持有Lock对象
Condition newCondition();
}
上記ロック(上)及びlockInterruptibly()メソッドで、以下の違いがあります。
ロック()メソッドは、ロックがスレッドのスケジューリングに関して利用できない場合、現在のスレッドが無効になっsynchronizedキーワードのロックを使用するのと同様であり、ロックを取得する前に、スレッドは休眠状態にありました。
名前が示唆するようにlockInterruptibly()メソッドは、ロックが使用できない場合、スレッドは、現在同期キーワードよりも柔軟である、中断することができる待っていることです。
クラシック・ロック・インターフェースの使用
Lock lock = new ReentrantLock();
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}
ReentrantLockの
ReentrantLock
クラスは、同一の機能を有すると同期、さらにロック待機限度を備え、かつ機能割り込みラッチロックの試みに加えて、再入排他ロックです。
ReentrantLock
下の層は、継承AQSを通じて排他ロック機能を達成することです。
公正かつ不公平なロックロック
ReentrantLock
:、学ぶために2つの非常に重要な概念があり、公正かつ不公平なロックロックが。
見るReentrantLock
のソースコードを、私たちは、対応する構造体が資本と非株式ロックロックに分けて、2つのコンストラクタが表示されます。
//默认构造非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//true构造公平锁,false构造非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
フェアロック:ロックをつかむために、障害がキューに入った後、スレッドを入力するキューが最初のロックを取得しますスレッドを指します。公平性が先着順を反映しています。
不公平ロックは:ロック障害が待ちキューに入りますつかむためにスレッドがありますが、ロックを取得するためのスレッドを待つことができた者は、最初に務めたが、ランダム最初に来るの規則に従っていません。不公平は、第一のロックを得ることができ、後続のスレッドに反映されます。
ロックで多くのスレッド公正な競争がある場合は上記のオーバーヘッドスレッドのスケジューリングが比較的大きいため、(多くの場合、極端に遅く、非常に遅い、である)システム全体のスループットは、比較的低いです。
その理由は、公正な戦術を使用している場合、スレッドがロックを解除するとき、あなたが最初に待ちキューのスレッドがウェイクアップする必要があることです。ウェイクアップスケジュールプロセスは、より多くの時間がかかります。あなたは非アームロックを使用する場合は、スレッドがロックを解放したとき、その後、スレッドはロック、より高い効率を取得、すぐに使用することができます。
ReentrantLockのコードの実装
1.ロックコードは不公平です
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//如果没有线程占据锁,则占据锁,也就是将state从0设置为1
//这种抢占方式不要排队,有人释放了锁,你可以直接插到第一位
//去抢,只要你能抢到
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//否则尝试抢占锁
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
AQSの導入の前にすることで、私たちは、押収したときにロックはtryAcquireメソッドを呼び出します知っています。アンフェアロック直接の親クラスを呼び出すために、この方法nonfairTryAcquire
。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//锁已经被释放,则直接占据锁
if (c == 0) {
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;
}
1.ロックコードフェア
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) {
//没人在队列中排队,并且锁已经被释放才能抢占到锁,否则去队列中排队
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;
}
}