java併発の重入錠-Rentrant Lockを詳しく説明します。
5574 ワード
前言
現在主流のロックは二種類あります。一つはsynchronizedで、もう一つはRentrant Lockです。JDK最適化はこれまでのsynchronizedの性能と再入力ロックは同じですが、再入力ロックの機能と柔軟性はこのキーワードより多いので、再入力ロックはsynchronizedのキーワードを完全に代替することができます。これを紹介します。
本文
RentrantrantLockの再入力ロックはロックインターフェースの中で最も重要な実現であり、実際の開発において最も多く使われているものです。この文章は実際に開発された応用シーンにより近いです。開発者に直接的な応用を提供します。ですから、すべての方法を説明しているわけではないです。ちょっと寒い方法があります。紹介したり、持ったりはしません。
まず、そのいくつかの構造方法を使用する必要があります。
RentrantLockは2つの構成方法を提供し、2つの宣言方式に対応しています。
第一の声明は公平なロックで、いわゆる公平な錠は時間の順序によって、先に待っているスレッドを先にロックさせます。そして、公平な錠は飢餓錠を発生しません。つまり、順番を待っていれば、最後に鍵を獲得する機会を待つことができます。
第二のステートメントは非公平ロックであり、非公平ロックという概念は逆であり、スレッド待ちの順序は必ずしも実行の順序ではなく、後から入ってくるスレッドが先に実行される可能性がある。
RentrantrantLockはデフォルトでは非公平ロックである。公平ロックは先に出る公平性を実現しているが、スレッドが来ると列に入るため、ブロックが必要になり、またブロックが運行に変わるので、このような文脈の切り替えは非常に性能的である。非公平ロックは割り込みが許されるため、文脈の切り替えが少なく、性能が優れ、大きなスループットが確保されますが、飢餓問題が起こりやすいです。ですから、実際に生産されているのも非公平ロックが多く使われています。
アンフェアロックではなく、NonfairSyncメソッドを呼び出します。
二、ロックをかけた後のロック方法はどうなりますか?
先ほど、私たちは不公平ロックなら、ノンフェアSync方法を呼出すると言っていましたが、この方法は何をしているのか見てみます。
読んだ前の預言者:RentrantLockはstateで「鍵を持っているスレッドはこのロックの回数を繰り返し取得した」と表しています。state(以下、状態二子で置換)が0に等しい場合、現在スレッドがロックされていないことを示します。
第1ステップはcompreAndSetState方法を呼び出し、第1パラメータは期待値0、第2パラメータは実際値1と伝えました。現在のこの方法は実際にunsafe.com mpareAndSwapIntを呼び出してCAS操作を実現しました。つまりロック前の状態は0でなければなりません。もし0呼び出しsetExclusive Owner Thread方法です。
二番目のステップは、compreAndSetState方法がfalseに戻るときに呼び出したのはacquire方法で、パラメータは1つです。
tryAcquire()方法は実際にnonfairTryAcquire()方法を呼び出した。
はい、これまでロックの現在のスレッドしか実行できなかった理由が分かりました。得られなかったのはキューの中でずっとCAS原理を利用してロックをしようとしました。
三、すべてのスレッドが実行されたら、unlock()メソッドを呼び出します。
unlock()方法はAQSのrelease(int)方法によって実現されます。
以上述べたのは小编が皆さんに绍介したjava并合の重入ロック-Rentrant Lockの详しい解统で、皆さんに助けを求めています。ここでも私たちのサイトを応援してくれてありがとうございます。
現在主流のロックは二種類あります。一つはsynchronizedで、もう一つはRentrant Lockです。JDK最適化はこれまでのsynchronizedの性能と再入力ロックは同じですが、再入力ロックの機能と柔軟性はこのキーワードより多いので、再入力ロックはsynchronizedのキーワードを完全に代替することができます。これを紹介します。
本文
RentrantrantLockの再入力ロックはロックインターフェースの中で最も重要な実現であり、実際の開発において最も多く使われているものです。この文章は実際に開発された応用シーンにより近いです。開発者に直接的な応用を提供します。ですから、すべての方法を説明しているわけではないです。ちょっと寒い方法があります。紹介したり、持ったりはしません。
まず、そのいくつかの構造方法を使用する必要があります。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
推奨ステートメント方式
private static ReentrantLock lock = new ReentrantLock(true);
private static ReentrantLock locka = new ReentrantLock();
重点説明:RentrantLockは2つの構成方法を提供し、2つの宣言方式に対応しています。
第一の声明は公平なロックで、いわゆる公平な錠は時間の順序によって、先に待っているスレッドを先にロックさせます。そして、公平な錠は飢餓錠を発生しません。つまり、順番を待っていれば、最後に鍵を獲得する機会を待つことができます。
第二のステートメントは非公平ロックであり、非公平ロックという概念は逆であり、スレッド待ちの順序は必ずしも実行の順序ではなく、後から入ってくるスレッドが先に実行される可能性がある。
RentrantrantLockはデフォルトでは非公平ロックである。公平ロックは先に出る公平性を実現しているが、スレッドが来ると列に入るため、ブロックが必要になり、またブロックが運行に変わるので、このような文脈の切り替えは非常に性能的である。非公平ロックは割り込みが許されるため、文脈の切り替えが少なく、性能が優れ、大きなスループットが確保されますが、飢餓問題が起こりやすいです。ですから、実際に生産されているのも非公平ロックが多く使われています。
アンフェアロックではなく、NonfairSyncメソッドを呼び出します。
二、ロックをかけた後のロック方法はどうなりますか?
先ほど、私たちは不公平ロックなら、ノンフェアSync方法を呼出すると言っていましたが、この方法は何をしているのか見てみます。
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() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
重点説明:読んだ前の預言者:RentrantLockはstateで「鍵を持っているスレッドはこのロックの回数を繰り返し取得した」と表しています。state(以下、状態二子で置換)が0に等しい場合、現在スレッドがロックされていないことを示します。
第1ステップはcompreAndSetState方法を呼び出し、第1パラメータは期待値0、第2パラメータは実際値1と伝えました。現在のこの方法は実際にunsafe.com mpareAndSwapIntを呼び出してCAS操作を実現しました。つまりロック前の状態は0でなければなりません。もし0呼び出しsetExclusive Owner Thread方法です。
private transient Thread exclusiveOwnerThread;
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
setExclusive OwneranterThreadはスレッドが現在のスレッドに設定されていることが分かります。スレッドの一つがロックされているということです。みんなCASの3つの値があります。古い値が予想値に等しいなら、新しい値を付与します。だから、現在のスレッドがロックされたら、状態を1にします。二番目のステップは、compreAndSetState方法がfalseに戻るときに呼び出したのはacquire方法で、パラメータは1つです。
tryAcquire()方法は実際にnonfairTryAcquire()方法を呼び出した。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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;
}
コメントでは、独占ロックを要求し、すべての中断を無視して、少なくとも一回のtryAcquireを実行し、成功すれば戻ります。そうでなければ、スレッドはブロックに入ります。2つの状態が切り替わります。tryAcquireが成功するまで。詳細はリンクtryAcquire()、addWaiter()、acquire Queued()によって分析されます。はい、これまでロックの現在のスレッドしか実行できなかった理由が分かりました。得られなかったのはキューの中でずっとCAS原理を利用してロックをしようとしました。
三、すべてのスレッドが実行されたら、unlock()メソッドを呼び出します。
unlock()方法はAQSのrelease(int)方法によって実現されます。
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease()はサブクラスによって実現されました。RentrantLockのSyncの実現を見てみます。
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;
}
まず、getStateを通じてステータスマークを取得します。このマークがリリースされる数量と等しい場合、現在の占有ロックのスレッドをnullに設定してロックのリリースを実現して、trueに戻ります。そうでない場合はステータスマークを差し引いてfalseに戻ります。以上述べたのは小编が皆さんに绍介したjava并合の重入ロック-Rentrant Lockの详しい解统で、皆さんに助けを求めています。ここでも私たちのサイトを応援してくれてありがとうございます。