5

次のコードを検討してください。奇数が発生しないように、スレッドセーフなクラスにします。

class Test {
  private int value = 0;
  private final Object lock;

  public void add() {
    synchronized (lock) {
      value++;
      value++;
    }
  }

  public int getValue() {
    synchronized (lock) {
      return value;
    }
  } 
}

私は今、最終的であると宣言されているロックフィールドに疑問を持っていますが、これは問題になりますか?またはそれはスレッドセーフを壊しますか?

ロックフィールドがfinalであると宣言されていない場合、これはスレッドセーフクラスである必要があると思います。この結論が間違っている場合は、私を訂正してください、ありがとう。

4

6 に答える 6

9

私は今、最終的であると宣言されているロックフィールドに疑問を持っていますが、これは問題になりますか?

はい、フィールドオブジェクトのみをロックすることをお勧めします。final

参照を変更できる場合は、ロックされているオブジェクトを変更して、スレッドセーフを破ることができます。

于 2012-07-13T20:42:21.103 に答える
1

大丈夫なはず。実行中にロックに何か他のものを単に割り当てることはできないので、それをより安全にするかもしれません。

于 2012-07-13T20:42:49.110 に答える
1

ReadWriteLockを使用して、同じ結果を安全な実装で実現できます。

参照:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html

http://www.javapractices.com/topic/TopicAction.do?Id=118

于 2012-07-13T20:43:35.553 に答える
1

インスタンスをロックする場合は、finalを使用できます。クラスにミューテックスをロックまたは配置する場合は、変数を静的にします。

于 2012-07-13T20:51:37.943 に答える
0

複数のスレッドを同期しようとする場合、同じオブジェクト参照/インスタンスに基づいて同期する必要があります。これにより、同じデータに基づいて両方が同時に同期することが保証されます。

それが少し理にかなっていることを願っています。動的変数ではなく、最終化された変数に基づいて同期する必要があります。

メソッドが静的フィールドを変更する場合、そのメソッドが通常は単一のスレッドによってのみ使用される場合でも、このフィールドへのアクセスを同期する必要があります。無関係のクライアントが同様に実行するという保証はないため、クライアントがそのような方法で外部同期を実行することはできません。を参照してください。

于 2012-07-13T20:54:28.610 に答える
0

Javaでは、同期はロックオブジェクトの非表示フィールドによって行われます。また、finalは、REFERENCEがオブジェクト自体ではなく、finalであることを意味します。

例:

final Bar bar = new Bar(); //bar hase property lock
bar.lock = XYZ; //will work, object is not FINAL
bar = new Bar(); //fail, the reference is FINAL
于 2012-07-13T20:42:34.307 に答える