[解決済み] synchronized(this)が使えるのに、なぜReentrantLockを使うのですか?
質問
を使用することができる場合、同時実行におけるロックがそれほど重要である理由を理解しようとしているのです。
synchronized (this)
. 以下のダミーコードでは、どちらも可能です。
-
メソッド全体を同期させるか、脆弱な部分を同期させるか(
synchronized(this){...}
) - または、脆弱なコード領域をReentrantLockでロックする。
コード
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
解決方法は?
A
リエントラントロック
は
非構造化
とは異なり
synchronized
つまり、ロックにブロック構造を使う必要はなく、メソッドをまたいでロックを保持することも可能です。例を挙げよう。
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
このようなフローは
synchronized
を構成します。
それはさておき。
ReentrantLock
サポート
ロックポーリング
と
タイムアウトをサポートする割り込み可能なロック待機
.
ReentrantLock
にも対応しています。
設定可能
公平性
ポリシー
より柔軟なスレッドスケジューリングが可能になります。
このクラスのコンストラクタには、オプションで
公平性
パラメータがあります。設定時
true
競合がある場合、ロックは最も長く待機しているスレッドにアクセスを許可することを優先します。そうでない場合は、このロックは特定のアクセス順序を保証しない。多くのスレッドからアクセスされるフェアロックを使用するプログラムは、 デフォルトの設定を使用するプログラムよりも全体のスループットが低下する (つまり、遅くなる、しばしばかなり遅くなる) かもしれませんが、ロックを取得する時間のばらつきが小さく、飢餓がないことが保証されます。ただし、ロックの公平性は、スレッドスケジューリングの公平性を保証するものではありません。したがって、公平なロックを使用している多くのスレッドのうちの1つは、他のアクティブなスレッドが進行しておらず、現在ロックを保持していない間に、連続して複数回ロックを取得することができます。また、時間制限のない
tryLock
メソッドは公平性の設定を尊重しません。他のスレッドが待っていても、ロックが利用可能であれば成功します。
ReentrantLock
よろしい
もあります。
よりスケーラブルに
より高いコンテンションでより良いパフォーマンスを発揮します。これについては、以下の記事をご覧ください。
こちら
.
しかし、この主張には異論もあり、以下のコメントをご覧ください。
<ブロッククオートリエントラントロックテストでは、毎回新しいロックが作成されるため、排他的ロックはなく、結果のデータは無効です。また、IBMのリンクは基礎となるベンチマークのソースコードを提供していないため、テストが正しく実施されたかどうかを判断することは不可能です。
どのような場合に
ReentrantLock
s? developerWorksの記事によると...
答えはとても簡単で、実際に必要なときに使うものです。
synchronized
例えば、時間指定ロック待機、割り込み可能ロック待機、非ブロック構造ロック、複数条件変数、ロックポーリングなどです。ReentrantLock
にもスケーラビリティの利点があり、実際に高いコンテンションを示す状況がある場合は使用すべきですが、大半のsynchronized
ブロックは、高いコンテンションどころか、コンテンションが発生することもほとんどありません。私は、同期が不十分であることが証明されるまでは、同期を使用して開発することをお勧めします。ReentrantLock
. これらは上級者のための高度なツールであることを忘れないでください。(そして、本当に上級のユーザーは、シンプルなツールが不十分であると確信するまでは、見つけうる限り最もシンプルなツールを好む傾向があります)。いつものように、まず正しいものを作り、それから速くする必要があるかどうかを心配することです。
もうひとつ、近い将来、より重要な意味を持つようになるであろう、以下の事柄に関連しています。
Java 15とProject Loom
. 仮想スレッドの(新しい)世界では、基本的なスケジューラは、よりよく動作するようになります
ReentrantLock
でできることよりも
synchronized
少なくともJava 15の初期リリースではその通りですが、後に最適化される可能性があります。
現在のLoomの実装では、仮想スレッドを固定できるのは、スタック上にネイティブフレームがある場合(Javaコードがネイティブコード(JNI)を呼び出し、それがJavaにコールバックされる場合)、および
synchronized
ブロックやメソッドで使用されます。これらの場合、仮想スレッドをブロックすると、それを担う物理スレッドもブロックされます。ネイティブコールが完了するか、モニターが解放されると (
synchronized
ブロック/メソッドが終了する)スレッドの固定が解除されます。
によってガードされた共通のI/Oオペレーションがある場合、そのI/Oオペレーションを実行するために
synchronized
に置き換えると、モニターは
ReentrantLock
を使えば、モニターによるピン留めを修正する前に、 Loom のスケーラビリティの恩恵を十分に受けることができます (あるいは、より性能の高い
StampedLock
可能であれば)。
関連
-
eclipse アクセス制限です。タイプ 'xxx' は API ではありません(必須ライブラリ '' の制限)。
-
Java コンパイルエラー - スレッド "main" で例外 java.lang.Error: 未解決のコンパイル問題です。
-
このラインで複数のマーカーを解決する方法
-
[解決済み] serialVersionUIDとは何ですか、またなぜそれを使用する必要がありますか?
-
[解決済み] ランダムな文字列を使用するこのコードは、なぜ "hello world" と表示されるのですか?
-
[解決済み] なぜゲッターとセッター/アクセッサーを使うのですか?
-
[解決済み] Stringでswitch文が使えないのはなぜですか?
-
[解決済み] Javaでsynchronized(this)を避けるには?
-
[解決済み】なぜwait()は常に同期ブロックの中になければならないのか?
-
[解決済み】Synchronized Blockの代わりにSynchronized Methodを使用する利点はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Java エラー報告 スレッド "main" での例外 java.util.NoSuchElementException
-
Java Exceptionが発生しました エラー解決
-
ファインバグタイプ
-
アクセス制限です。タイプ 'Application' は API ではありません。
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 0 at One1.main(One1.java:3)
-
javaコンパイル時のエラー:不正な文字 '\ufeff' に対する解決策です。
-
spring aop アドバイスからの Null 戻り値が、サマリーのプリミティブ戻り値と一致しない。
-
mavenプロジェクトのテストエラー java.lang.ClassNotFoundException: org.glassfish.jersey.client.ClientConfig の問題を解決する。
-
スレッド "main" で例外発生 java.net.BindException: アドレスは既に使用中です。NET_Bind
-
コミットには何も追加されないが、未追跡のファイルが存在し、gitで未追跡のファイルに対する完璧な解決策