この記事は、6つの部分に分かれて分類異なる特性、同時ロックの異なるデザインをロックし、ロックのエスカレーション、ReentrantLockのあなたは、Javaの同時実行のロックおよび関連事業整理に役立ちますReadWriteLockアプリケーションに同期されます。
ロックされた分類
一般的に、我々はこれらのロックは、以下の通り述べました。
- 楽観/悲観的ロックをロック
- ロックフェア/不公平ロック
- リエントラントロック
- 排他ロック/共有ロック
- ミューテックス読み取り/書き込みロック
- セグメント化されたロック
- 偏ったロック/ロック軽量/ヘビー級ロック
- スピンロック
上記、これらのカテゴリは、すべてのロック状態にロックする用語の多く言及されていないが、いくつかのロックの特性を参照して、ロックの設計は、いくつかのことをいう、以下に説明されます。
1、VS悲観的楽観的ロックロック
広い概念で楽観と悲観的ロックロックは、異なる角度のスレッド同期のビューを反映し、およびJavaデータベースの実用的なアプリケーションは、対応する概念です。
(1)楽観的ロック
名前が示すように、など、それはロックされませんので、他の人が変更されていないことを毎回データをピックアップし、非常に楽観的ですが、更新は、この時間の間に他の人がデータを更新するために行かなかった、あなたはバージョン番号を使用することができるかを決定する時期メカニズム。
オプティミスティック・ロックを読み込むためのアプリケーションの種類に適しており、Javaで楽観的ロックは、ロックフリーのプログラミングを使用することによって達成される、最も一般的に使用されるアルゴリズムは、CAS、CASによって達成スピンのアトミックインクリメント動作するJavaクラスがあります。
CASフルコンペア・アンド・スワップ(比較交換)、ロックフリーアルゴリズム。それは(何のスレッドがブロックされていない)ロックを使用せずに複数の変数間のスレッドの同期を実現します。原子クラスjava.util.concurrentパッケージは、CAS楽観的ロックによって達成されます。
簡単に言えば、CASアルゴリズムは、3つの3つのオペランドがあります。
- あなたは、メモリ値Vを読み書きする必要があります
- A.を比較する値
- B.の新しい値を書き込むには
期待値V Aと同じメモリの値は、メモリの値VはBのように変更した場合にのみ、そうでない場合はV. これは、それが変わる前に、私はそれを信じて、それを修正するために、他のスレッド思考の楽観的ロックではありません。そして同期は悲観的ロックです、それは変わる前に、それを修正するために他のスレッドがあるだろうと考えて、ペシミスティック・ロック・効率非常に低いです。
(2)悲観的ロック
それはロックを得たまで、常に最悪のケースを想定し、データが、彼女はデータを取ったたびにロックされますので、人々は、このデータを取りたいので、他の人は、変更になる得るために考慮されるたびにブロックされます。
従来のリレーショナルMySQLデータベース内のこのような行等ロック、テーブルロック、リードロック、ライトロック、このロック機構の多くを使用するように、第1の動作を実行する前にロックされています。
- 多くの動作シナリオを書くための悲観的ロックは、第1ロック性を保証は、正しいデータが書き込み動作をすることを。
- 操作シーンのためのより楽観的ロックを読んで、ロック解除の機能が大幅に読み取り操作のパフォーマンスを向上させることを可能にします。
2、公正かつ不公平ロックロックVS
(1)フェアロック
それ以外の場合はに追加されます、待ちキューロックメンテナンスを取得する際、それが空の場合、並行環境で、各スレッドは最初、このロックが表示されます、または現在のスレッドがキューで待機している、それがロックを占め、非常に公平ですキューで待機して、将来は自分自身へのFIFOキューからのルールに従って行われます。
ロックスレッドが餓死しませんのために公正なロックの利点が待っています。欠点はブロックされ、CPUオーバーヘッドブロッキングスレッドが非公平ロックよりも起こされているすべてのスレッドの最初のスレッドに加えて、キュー待ち、全体のスループット効率は、非アームロック比較的低いことです。
(2)非エクイティ・ロック
最大直接、同様のフェアは、そのようにロックし、試行が失敗した場合、ロックを持ってしてみてください。
スレッドがロックへの直接のアクセスをブロックしないようにチャンスを持っているので、CPUは、すべてのスレッドを覚ます必要がない、不当な優位性を想起スレッドのオーバーヘッド削減、高全体のスループット効率がされるロック。欠点は、待ち行列のスレッドで餓死したり、ロックを取得する前に長い時間を待つことです。
(3)代表的なアプリケーション
フェアロックの新しいReentrantLockの(真の)実装を使用することができます。java JDKと契約ReentrantLockの中には、次のようなは、公正かつ不公平ロックロック(デフォルト)を作成するために、ブール型コンストラクタを指定することができます。
3、共有ロック排他ロックVS
(1)排他ロック
ロックは唯一のスレッドによって保持させることができることを意味しています。
(2)共有ロック
ロックは、複数のスレッドによって保持させることができることを意味しています。
関係のJava ReentrantLockのために、それは排他ロックです。しかし、別のクラスのためにロックを読んで実装ReadWriteLockロックは、ロックが排他的な書き込みロックである、共有ロックであること。
- ロック性を保証を読み取るために、ロックを共有同時読み取り、書き込みは、書き込みは、読み取り、書き込みプロセスは、相互に排他的で、非常に効率的です。
- 排他ロックと共有ロックは排他的または共有を実現するためにさまざまな方法を実装することにより、AQSによって達成されます。
(3)AQS
抽象キューシンクロナイザ(AQSと呼ばれるAbstractQueuedSynchronizerは、)によって取得されたリソースを完了するために、同期状態を維持するために、揮発性変数の整数(指定された状態)を使用してベースフレームまたはアセンブリの他の同期ロックを構築するために使用される内蔵FIFOキューキューワーカースレッド。
示さ読む、AQS、非ブロックデータ構造と変数クラスの原子構造の上に示され、などが基本クラス変数/ CAS及び書き込みが実装、およびロック、シンクロナイザのブロッキングキュー、エグゼキュータとコンカレント・コンテナーなどの揮発性に基づいているとして、同時パッケージを実装およびその他の上級クラスは、基本クラスの実装に基づいています。
4、読み書きロックミューテックスVS
二つの主要なプロセス、同期と相互排他の交点との間の関係。排他的な、いわゆる、実行中のプログラムフラグメントは、他のプロセスがそれらの間で任意のプログラムフラグメントを実行することはできませんするプロセスは、これだけのプロセスが終了するまで待つことができ、異なるプロセス間で散在プログラムフラグメントの数を指し、実行されています彼らは実行する前にプログラムが断片化します。いわゆる同期は、異なるプロセス間で散乱プログラムフラグメントの数を指し、それらの動作は、いくつかを実行するための規定に厳密に従ってなければならず、これは達成するための特定のタスクの順序に依存しています。
明らかに、より洗練された同期が相互に排他的であるが、相互に排他的で特別な同期です。
それは彼らが相互に排他的で、同時に実行するために、2つのスレッド間で相互に排他的ではない、我々は、他の完成ランニングを実行するためにしたスレッドを待機しなければならない、と同期が同時に実行されていないが、彼は、特定の順序に応じて安全でなければなりません対応するスレッド(も相互排他)を実行するには!
概要:相互に排他的では:それにアクセスするための唯一の訪問者を可能にしながら資源であり、ユニークかつ排他的です。しかし、訪問者がアクセスが注文されていないこと、リソースの排他的秩序へのアクセスを制限することはできません。
同期:訪問者が他の機構を通じて資源への整然としたアクセスを実現、(ほとんどの場合)相互に排他的で根拠を指します。ほとんどの場合、相互排他同期は相互に排他的である必要があり、特にすべてのリソースを書き込む場合には、達成されています。まれに同時にアクセス複数のリソースへの訪問者を許可することができるものではありません。
(1)ミューテックス
共有リソースにアクセスする前に、アクセスが完了した後にロック動作、ロック解除操作を実行します。ロックした後、再ロックする他の試みは、スレッドがロックを解除するために、現在のプロセスまでブロックされるであろう。
以上のスレッドよりもロックを解除し、すべてのロックされたスレッドがプログラム準備ができている場合、最初のスレッドがロック操作を実行する準備ができてとなっているブロックされ、その後、他のスレッドが入るようにお待ちしておりますがあります。このように、1つのスレッドのみ保護されたリソースのミューテックスにアクセスすることができます
(2)読み取りと書き込みロック
それは読み書きロックに入って来た。この時間は、書き込みロックは汎用性の高い技術であり、Javaは一意ではありません。
読み書きロックの特徴:
- 読者は同時に複数を読むことができます
- 作家は、相互に排他的でなければなりません(書き込みのみにライターを可能に、また同時に書き込みに読者)
- 読者のためにプラスを書く(ライターたら、読者はウェイクアップを書く人たちを優先し、フォローアップを待つ必要があります)
ミューテックスの特長:
- あなたが唯一のスレッドのミューテックスを持つことができ、他のスレッドが待機しなければなりません
(3)Linuxの読み書きロックを
Linuxは、カーネルの支持体は、読み書きロックを。
互斥锁
pthread_mutex_init()
pthread_mutex_lock()
pthread_mutex_unlock()
读写锁
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_wrlock()
pthread_rwlock_unlock()
条件变量
pthread_cond_init()
pthread_cond_wait()
pthread_cond_signal()
5、スピン・ロック
スピンロック(スピンロック):それはロックが他のスレッドによって取得された場合、スレッドは、ロックを獲得するための時間を指すロックが前に取得されるまで、スレッドは、サイクルを待ち、その後ロックが正常に取得されているかどうかを決定していきループを抜けます。
Javaでは、スピンロックの代わりにロックを取得しようとする循環方式を使用する、直ちにブロックしないロック・スレッドを取得する試みを指し、この利点は、スレッドコンテキストスイッチの消費を低減することであり、欠点は、サイクルはCPUを消費することです。
典型的な例スピンロック実装、参照を実装することができるスピンロック
共有資源の保護とロック機構を実現することが提案されています。実際には、スピンミューテックスロックとより類似した、彼らは排他的なリソースの使用に対処するために作られています。ミューテックスやスピンロックかどうか、任意の時点で、唯一のあなただけのロックを取得するための任意の時点で、ほとんど一つの実行単位で持つことができ、それは言った、ホルダーを持つことができます。しかし、わずかに異なる2つのスケジューリングメカニズム。リソースが既に占有されている場合、ミューテックスの場合は、リソース要求はスリープ状態に入ることができます。
しかし、睡眠への発信者を引き起こすことなく、スピンロックに、スピンロックが別の実行ユニットを開催されている場合、呼び出し側は、スピンサイクルロックホルダは、単語「スピン」ロックをリリースしているかどうかを確認することでしたそれは、そのように命名されます。
Javaのスピンロックを実装する方法(1)?
ここでは簡単な例です:
public class SpinLock {
private AtomicReference<Thread> cas = new AtomicReference<Thread>();
public void lock() {
Thread current = Thread.currentThread();
// 利用CAS
while (!cas.compareAndSet(null, current)) {
// DO nothing
}
}
public void unlock() {
Thread current = Thread.currentThread();
cas.compareAndSet(current, null);
}
}
正常に取得することができるロックを取得する最初のスレッドCASロックの方法()、ロックがこの時間スレッドAで放出されていない場合、whileループに入らず、B、再びこの時間をロックを取得するために別のスレッドスレッドがロック、アンロック方式のリリースを呼び出すまで絶えず、CASかどうかを判断し、彼らはwhileループに入ります、CASを満たしていません。
(2)スピンロックの問題が存在します
- スレッドが長すぎるためにロックを保持している場合、それは、待ちにループにロックを取得するために待機している他のスレッドにつながるCPUを消費します。不適切に使用すると、高いCPU使用率を引き起こす可能性があります。
- 上記のスピンロックのJava実装は、ロックの最長待機しているスレッドの優先アクセスを満たすことができないこと、公平ではありません。アンフェアロックは、「スレッドの不足」の問題を存在します。
(3)スピンロックの利点
- スレッドがブロック状態に入らせない、不必要なコンテキストスイッチングを低減する、実行速度、スピンロック状態は、スレッドスイッチは、ユーザモードであった発生、すなわち、スレッドがアクティブであったことはありません
- ノンスピンロックの取得時間は必要がスレッドコンテキストスイッチのために、カーネルモードから回復したときにロックが取得されると、カーネル状態に入るように、ブロックされた状態にロックされません。(カーネルスレッドが(Linux)のスケジューリング状態に入った後にブロックされ、これは深刻なロックのパフォーマンスに影響を与え、システムがユーザーモードとカーネルモードの間で前後に切り替えることになります)
第二に、並行処理に異なるデザインアプローチ
ロックの設計やアプリケーションに応じて、ロックセグメントは、読み書きロックのように、持っています。
1、ロックセグメント技術、並行処理に1デザイン
ロックはConcurrentHashMapのために、その実装は、セグメントの形でロックの効率的な同時動作を実現するために複雑で、実際にロックセグメント設計ではなく、特定のロックです。
内部項目配列を有するHashMapのと同様であり、その構造(HashMapの実装でJDK7とJDK8)、アレイセグメントと呼ばれるロックセグメントを意味し、セグメント化されたロックデザイン、のConcurrentHashMapを探すためのConcurrentHashMap各要素は、リンクされたリストであり、それはまた、ReentrantLockの(ReentrantLockの継承セグメント)です。
あなたは要素を配置する必要がある場合、全体のハッシュマップはロックされていないが、彼はセグメントをつけたいことを知って最初の、そしてセグメントは、ハッシュコードでロックされ、その複数のスレッドが時間をかけたときにして、セグメント上の長いほどではない、真の並列挿入を達成します。
あなたがロックの統計にセグメントのすべてを取得する必要がある場合しかし、当時の統計サイズが、私はハッシュマップのグローバルな情報を得ることができます。
動作時間は、それが唯一つのアレイに対してロック操作を行った場合、ロックセグメント改良ロック粒度するように設計され、アレイ全体を更新する必要はありません。
ロック及びロック膨張(粗大化)を除去するため2、
ロックは必要でないならば、排除する、ロックを使用しないでください。Java仮想マシンによると、コード効率を向上させる機会を排除するために、スレッドセーフな、確認された場合、スレッドセーフな仮想ロックをロックされているかどうか。決定するために分析を逃れることができます
ロック粗大化。コードの必要性の一部は、複数のロックを使用する場合、効率を改善するために、ロックのより大きな範囲を使用することが推奨されます。私たちは、同じオブジェクトのロックロックロック解除に一連の動作を、時間のかかるロックを減らすために粗大ロックへの仮想機会を見つけた場合、Java仮想マシンが最適化されます。
3、ロック付きポーリング時間ロック
スレッドロックによってポーリングは、常により良いエラーのシナリオを処理することができ、デッドロックを回避するために、達成するためにロックを取得しようとしています。Javaは、のtryLockメソッド呼び出しロックによってポーリングすることができます。tryLock方法は、支持体タイミングは、待ち時間は、パラメータ取得ロックで指定することができる実装を提供します。あなたがロックを取得できた場合は、直ちにまたは戻りにいくつかの時間を待った後、すぐにそれを返します。
4、読み書きロック
読み書きロックは優雅ReentrantReadWriteLockとして具現化リソースに対するアクセス制御を実装するReadWriteLock。読み書きロックは読み提供し、書き込みには2つのロックをロックし、データを読み込むときにデータを書き込む場合、書き込みロックの使用を読み取りロックを使用します。
読み書きロックは、同時に複数の読み取り操作を可能にするが、唯一の書き込み動作が実行されることができます。書き込みロックがロックされていない場合は、ロックは、読み取り、書き込みまたは完了を待つ必要がブロックされません。
ReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
三、ロックに同期
同期コードブロックは子monitorenter / monitorexit命令の組によって達成される、モニタオブジェクトは、基本的にはユニットを同期化されます。
Java 6の前に、完全にので、ユーザ・モード・カーネルモードを切り替える必要があるため、同期動作が未分化ヘビー操作で、内部のオペレーティング・システム・ミューテックスにモニタ達成されます。
ロックスキュー(偏ったロック)、ロック・軽量:これは劇的に三つの異なるモニタの実装を提供し、改善されてきた近代JVM、中(オラクル)JDKは、3つの異なるロックということが多いといわれています大幅に性能を向上ヘビーロック、。
1、ロック状態で同期
ロック状態は、ヘッドを示すために、モニタのオブジェクトフィールドにオブジェクトによって確立されます。
4つの状態がエスカレート状況と競合し、プロセスがダウングレードすることができないこと、不可逆的です。
これらの4つの状態が、Java言語でロックされますが、JVMの最適化(同期使用している場合)を取得し、ロックを解除の効率を改善し、実行するためにされていません。
- ロックフリー状態
- バイアスされたロック状態
- 軽量ロック状態
- ヘビー級のロック・ステータス
2、ロック、ロック、軽量、ヘビー級ロックする傾向があります
3つのロックは、ロック状態を参照し、同期するためのものです。Java 5の中でロックのエスカレーションを導入することにより、効率的な同期メカニズムを実現しています。スリーロック状態がヘッドを示すために、モニタのオブジェクトフィールドにオブジェクトによって確立されます。
同期符号のためのバイアスされたロック手段はスレッドによってアクセスされ、その後、スレッドは自動的にロックを取得します。ロックを取得するためのコストを削減します。
ロック時間をロックする付勢されている場合、別のスレッドによってアクセスされること軽量ロック手段、それは軽量バイアスロックロックにアップグレードされ、別のスレッドは、スピンの形でロックを取得しようとし、ブロックしない、パフォーマンスを向上させます。
ヘビー級のロック手段別のスレッドかかわらずスピンのときロックは軽量ロックですが、スピンは最後の永遠に、スピン一定回数は、まだロックを取得していないとき、障害物になりますないときロックインフレヘビー級ロック。ブロックのパフォーマンスに他のアプリケーションを作るためにヘビー級スレッドロック。
3、同期ロックのアップグレード
いわゆるロックのアップグレード、ダウングレード、JVMが異なる競争力の状況を検出すると、JVMの最適化の同期操作のための機構であり、これを自動的に達成するために、適切なロックに切り替わりますスイッチのアップグレード、ダウングレードをロックすることです。
何の競争が発生していない場合は、ロックを偏向するようにデフォルト設定されます。JVM(比較およびスワップ)を使用してCAS操作は、スレッドIDマークWordがヘッド部は、現在のスレッドに向かってオブジェクトを表現するために提供されるオブジェクトは、実際のミューテックスを含みません。そのためには、多くのアプリケーションシナリオでは、オブジェクトのほとんどは競争せずにコストを削減することができ、ロック偏向を使用し、スレッドのロックのライフサイクルを最大になるという仮定に基づいています。
別のスレッドがすでにオフに偏向ターゲットをロックしようとした場合、JVMは、軽量ロックを達成するために(REVOKE)撤退するスキューロックやスイッチが必要になります。軽量ロック依存CAS操作マーク・ワードは、再試行が成功した場合、軽量ロックを使用するのが一般的である、ロックを取得しようとする、そうでない場合は、さらにヘビー級ロックにアップグレード。
第四に、ルックReentrantLockの
ReentrantLockの、リエントラントミューテックスのうち、それがアクセスsynchronizedメソッドや文を使用して、同じ暗黙の監視ロックの基本的な振る舞いと意味を持っていますが、より強力な。
1、基本的な使い方
public class LockTest {
private Lock lock = new ReentrantLock();
public void testMethod() {
lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName()
+ (" " + (i + 1)));
}
lock.unlock();
}
}
2、条件申請
同期及び待機()とnitofy()/のnotifyAll()メソッドは、待機/通知モデルと併せて実施することができる、それは同様にReentrantLockのであってもよいが、条件を必要条件とより良い柔軟性がで具現:
- 複数の条件インスタンスよりも作成することができますロック、マルチチャンネルの通知
- 通知された場合()メソッドを通知する、スレッドがランダムに選択されたJava仮想マシンに通知されるが、ReentrantLockの選択的結合条件通知を実現することができ、それは非常に重要です
3、条件オブジェクトクラスとクラス
- 条件クラスObjectクラスと同等awiat方法および待機方法
- この方法は、信号方式及び条件クラスオブジェクトクラスと同等に通知します
- メソッドとメソッドsignalAll条件クラスObjectクラスと同等のnotifyAll
第五に、ReadWriteLock見
同時実行シナリオでスレッドの安全性の問題を解決するために、我々は、ほとんど排他的ロックの使用頻度が高い、一般的に使用されるキーワード同期が提供するJava(あなたは同期でこの記事を見ることができる)、またはconcurrentsパッケージを実装するインタフェースをロックしていますReentrantLockの。
彼らはあることを、一つだけのスレッドが同時にロックを取得することができ、ロックを獲得するために排他的です。データのみを読み取ることがあれば、データは(ダーティリードを表示されます)有効性には影響しない場合は、このビジネスシナリオでは、まだ排他的ロックを使用する場合、いくつかのビジネスシナリオでは、ほとんど唯一、めったにデータ、書き込みデータを読みませんそう、パフォーマンスのボトルネックの代わりになることは明らかです。
この小さな読み取りおよび書き込みの場合には、JavaはまたReentrantReadWriteLock(読み書きロック)ロックが別のインタフェースを実現提供します。読むと、複数のスレッドによるアクセスを許可され、同じ時間を書くには読みますが、スレッドへの書き込みアクセス、すべてのスレッドが読み書き他のスレッドがブロックされています。
1、ReadWriteLockインタフェース
ReadWriteLock、Guming Siの李、読み書きロックを、それが読み取り、読み取りロック、書き込み時には、書き込みロックを、同期パフォーマンスの問題に独創的な解決策であるように、時:読み取り間の相互排他と読みます。
ReadWriteLockは、次のようにインターフェイスのプロトタイプは次のとおりです。
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
ロックを読み書きするためのインタフェースのみ二つの方法。
言い換えれば、我々は、読むことができますし、互いに独立して、相互に排他的な読み取りと書き込み、書き込みと書き込みの相互に排他的な読まないスレッドに割り当てられる2つのロックに分け、あなたが個別に読み書きできる、ファイルを書き込みますファイルの読み込みと書き込みの効率を向上させます。
2、ReentrantReadWriteLockアプリケーション
次の例では、読み書きを、「Javaの並行プログラミングのアート」を参照して実装されたキャッシュをロックします。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache {
static Map<String,Object> map = new HashMap<String, Object>();
static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
public static final Object getByKey(String key){
readLock.lock();
try{
return map.get(key);
}finally{
readLock.unlock();
}
}
public static final Object getMap(){
readLock.lock();
try{
return map;
}finally{
readLock.unlock();
}
}
public static final Object put(String key,Object value){
writeLock.lock();
try{
return map.put(key, value);
}finally{
writeLock.unlock();
}
}
public static final Object remove(String key){
writeLock.lock();
try{
return map.remove(key);
}finally{
writeLock.unlock();
}
}
public static final void clear(){
writeLock.lock();
try{
map.clear();
}finally{
writeLock.unlock();
}
}
public static void main(String[] args) {
List<Thread> threadList = new ArrayList<Thread>();
for(int i =0;i<6;i++){
Thread thread = new PutThread();
threadList.add(thread);
}
for(Thread thread : threadList){
thread.start();
}
put("ji","ji");
System.out.println(getMap());
}
private static class PutThread extends Thread{
public void run(){
put(Thread.currentThread().getName(),Thread.currentThread().getName());
}
}
}
3、書き込みロック劣化ロック
読み書きロックのサポートロックダウングレードは、書き込みロックに従い、買収に続いて、その後、書き込みロックに読み取りロック、書き込みロックが読み取りロックを降格することができるようにするを取得するために解放する、ロックエスカレーションがサポートされていない、以下ReentrantWriteReadLockソースコードから取得されたサンプルコードにダウングレードロック:
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}