プリミティブ型の取得/セッターは、マルチスレッドアプリケーションでReadWriteLockでロックされるべきですか?
-
14-11-2019 - |
質問
マルチスレッドアプリケーションで使用されるJavaクラスを持っています。同時アクセスは非常に可能性が高いです。複数の同時読み取り操作はブロックされてはいけませんので、ReadWrite Lockを使用しています。
class Example {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private int i;
private boolean b;
public int getI() {
lock.readLock().lock();
final int tmp = i;
lock.readLock().unlock(),
return tmp;
}
public void setI( final int i ) {
lock.writeLock().lock();
this.i = i;
lock.writeLock().unlock();
}
public boolean getB() {
lock.readLock().lock();
final boolean tmp = b;
lock.readLock().unlock(),
return tmp;
}
public void setB( final boolean b ) {
lock.writeLock().lock();
this.b = b;
lock.writeLock().unlock();
}
}
.
簡単のため、この例のロックの周りのtry...finally
ブロックを省略しました。
プリミティブ型のゲッターとセッターをロック/同期させるために必要な(またはお勧めしました)必要があるか疑問に思いますか?Javaでの割り当て操作とリターン操作がアトミックです。ただし、これらのロックを使用することで、すべてのアクセサリが最新の値を取得することを確認してください(volatile
の使用に等しい)?
プリミティブがdouble
またはlong
の場合はどうですか?
解決
は依存します。 ただし、通常は粗いレベルで操作を同期させる必要があります。たとえば、これです。
Example e = ...;
synchronized (e) {
e.setI(e.getI() + 10);
}
.
そのようなシナリオの場合、内蔵ロックは冗長です。したがって、内部同期ではなく、これらのオブジェクトを使用する外部同期を適用することをおそらく適用することをお勧めします。
他のヒント
マルチスレッドアプリケーションではうまく機能するJavaのAtomicintegerのようなものがあります。
このクラスを不変クラスとして実装できる場合は自分自身に尋ねます。それは協力が簡単になり、本質的にスレッドセーフになります。並行性、ロック、同期などを心配する必要はありません。
不変クラスの例:
final class Example {
private final int i;
private final boolean b;
public Example(int i, boolean b){
this.i = i ;
this.b = b;
}
public int getI() {
return i;
}
public boolean getB() {
return b;
}
}
. アプリケーションをデザインするように、このような生データ型への同時アクセスがないようにします。そのような低レベルのロックを追加すると、アプリケーションをそんなに遅くする可能性が高いため、アプリケーションをマルチスレッド化する価値がありません。
e.g。完全にスケーリングし、1コアよりも32倍速を実行する32のコアシステムがあります。ただし、ロックされていないフィールドアクセスは1つのNSを取りますが、ロックは1 US(1000 ns)を取ります。(1000遅く/ 32速い)あなたが4つのコアしかない場合、それは何百回倍も遅くなる可能性があり、そもそもマルチスレッドを持つ目的を軽減します。
プリミティブ型の取得/セッションをロック/同期させる必要はありません。
前の投稿の一つとして言及して、読み取りと更新シーケンス、gententi(int num)のようなものである可能性があるものは、geti()とseti()を呼び出す可能性があります - この場合は「同期化」を追加することができますサンプルクラスにインクリメンタ(int num) 'メソッド。その後、ロックはより高いレベルで行われ、データや行動が一緒に留まるので、個別の読み書きロックの必要性を減らすことができます。この手法は、一度に複数のフィールドを読み/更新している場合はさらに便利です。
単に一度に1フィールドの読み書き/更新の場合、AtomicXXクラスはより適切なです。
プリミティブ型、文字列(不変の)およびスレッドセーフタイプ( "コンカレント"パッケージからのコレクションなど)にロックを使用しないでください。