このスタックオーバーフローのトピックを読みましたが、その結論は、空のsynchronized
ブロックはより良い解決策で常に回避できるということです。このトピックには、私にとって不明確な部分もいくつかあります。これは、以下の投稿に統合します。
次のようなクラスがあるとします。
public class MyThreadClass extends Thread {
private final OtherComponent mOtherComponent;
private final Object mLock = new Object();
private MyHandler mHandler;
public MyCustomThread(OtherComponent otherComponent) {
mOtherComponent = otherComponent;
public void run() {
mHandler = new Handler() {...}
// Other init operations
mOtherComponent.onMyCustomThreadInitialized();
// ... other operations (Looper.loop(), actually)
}
public void sendMessageWithHandler(int what, int arg) {
synchronized (mLock) {}
Message msg = mHandler.obtainMessage(what);
msg.arg1 = arg;
mHandler.sendMessage(msg);
}
public void useHandlerInAnotherWay(...) {
synchronized (mLock) {
// useful code that needs actual mutual exclusion
}
mHandler.sendMessage(...);
}
}
私のアプリケーションの関連部分は、次のように機能します。
MyThreadClass
スレッドが作成され、開始されます。- の間接的な結果として
mOtherComponent.onMyCustomThreadInitialized()
、アプリケーションの別の部分が他のスレッドの生成を開始します。(これらはこの呼び出しから同期的に開始されないことに注意してください。それが間接的な結果であると私が言う理由です。唯一のポイントは、mHandler
これらの他のスレッドが開始されるまでに初期化されていることです) - 他の各スレッド
sendMessageWithHandler(...)
は1 回だけ呼び出します - さらに、他のスレッド (つまり、上記のスレッドではない) が を呼び出します
useHandlerInAnotherWay(...)
。これはいつでも (mOtherComponent.onMyCustomThreadInitialized()
もちろん の後) 発生する可能性があります。
私の質問:
私が正しければ、はフィールドではないため、
mHandler
以外のスレッドからアクセスされたときに、最新のデータの可視性を保証する必要があります。これらのいくつかの呼び出しを除いて、同期なしで他のスレッドから使用されないため、私もそれを作成したくありません (オーバーヘッドが不要な場所に不必要に存在することは望ましくありません)。つまり、を介してこれらのさらに他のスレッドからアクセスされる場合、「有用なコード」(つまり、実際には相互排除の対象となる必要があるコード) を含む は、呼び出し元のスレッドが正しく認識することも保証します。ただし、では、コードは相互排除を必要としません。myThreadClass
final
volatile
sendMessageWithHandler(..)
mHandler
volatile
mHandler
useHandlerInAnotherWay()
synchronized
mHandler
sendMessageWithHandler(..)
sendMessageWithHandler(...)
. これは正しいです?私の問題に対するより良い解決策はありますか?私がリンクした他のスタックオーバーフロースレッドには、次の回答があります(受け入れられたものではありませんが、複数回賛成されました):
以前は、特定のメモリ バリア操作が発生することを仕様が暗示していました。ただし、現在は仕様が変更されており、元の仕様は正しく実装されていません。別のスレッドがロックを解放するのを待つために使用できますが、別のスレッドが既にロックを取得していることを調整するのは難しいでしょう。
これは、エンプティ
synchronized
がメモリバリア機能を提供しなくなったことを意味しますか? についてJavaドキュメントをオンラインで確認するsynchronized
と、すべてのメモリが更新されることが言及されています(つまり、モニターの開始時に「メインメモリ」からスレッドのコピーが更新され、モニターの終了時にスレッドのコピーから「メインメモリ」が更新されます)。しかし、彼らは空のブロックについて何も言及していないsynchronized
ので、これは私には不明です.