2

マルチスレッドアプリケーションで使用されるJavaクラスがあります。同時アクセスの可能性が非常に高くなります。複数の同時読み取り操作はブロックされるべきではないので、ReadWriteロックを使用しています。

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ますか?

4

6 に答える 6

4

場合によります。

ただし、通常は、次のように、より粗いレベルで操作を同期する必要があることに注意してください。

Example e = ...;

synchronized (e) {
    e.setI(e.getI() + 10);
}

このようなシナリオでは、内部ロックは冗長です。したがって、内部同期ではなく、これらのオブジェクトを使用する場所に外部同期を適用する方がよい場合があります。

于 2011-02-16T08:56:59.497 に答える
3

JavaのAtomicIntegerのようなものがあり、マルチスレッドアプリケーションでうまく機能します。

于 2011-02-16T09:29:05.153 に答える
2

このクラスを不変のクラスとして実装できるかどうかを自問してください。作業が簡単になり、本質的にスレッドセーフになります。同時実行、ロック、同期などについて心配する必要はありません。

不変クラスの例:

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;
    }
}
于 2011-02-16T08:56:37.793 に答える
2

このような生データ型に同時にアクセスできないようにアプリケーションを設計します。このような低レベルのロックを追加すると、アプリケーションの速度が低下する可能性が高いため、アプリケーションをマルチスレッド化する価値はありません。

たとえば、完全に拡張でき、1コアよりも32倍高速に実行される32コアシステムがあるとします。ただし、ロックなしのフィールドアクセスには1 nsかかり、ロックありの場合は1 us(1000 ns)かかるため、最終的にアプリケーションの処理速度は最大30倍遅くなる可能性があります。(1000低速/ 32高速)コアが4つしかない場合は、数百倍遅くなる可能性があり、そもそもマルチスレッドを使用するという目的に反します。私見では。

于 2011-02-16T09:12:09.910 に答える
2

プリミティブ型のゲッターとセッターをロック/同期する必要はありません-ほとんどの場合、揮発性としてタグ付けするだけで十分です(2倍とあなたが言及している限り)

以前の投稿の1つで言及されているように、読み取りおよび更新シーケンスに注意する必要があります。たとえば、getI()およびsetI()を呼び出すincrementI(int num)のようなものです。この場合、'同期されたincrementI(int num)'メソッドをExampleクラスに追加します。その後、ロックはより高いレベルで実行され、個別の読み取りロックと書き込みロックの必要性が減り、データと動作が一緒に保たれるため、OOに対応します。この手法は、一度に複数のフィールドを読み取ったり更新したりする場合にさらに役立ちます。

単純に、一度に1つのフィールドを読み取り/書き込み/更新する場合でも、AtomicXXクラスの方が適切です。

于 2011-02-16T21:46:47.123 に答える
0

プリミティブ型、文字列(不変)、およびスレッドセーフ型(「並行」パッケージからのコレクションなど)へのロックは使用しないでください。

于 2011-02-16T09:01:10.383 に答える