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 的 lock 字段表示怀疑,这有关系吗?还是会破坏线程安全?

我认为如果锁字段没有声明为最终的,这应该是一个线程安全的类。如果这个结论是错误的,请纠正我,谢谢。

4

6 回答 6

9

我现在对宣布为 final 的 lock 字段表示怀疑,这有关系吗?

是的,它被认为是仅锁定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

在 Java 中,同步是由锁定对象的某个隐藏字段完成的。同样 final 意味着 REFERENCE 是最终的,而不是对象本身。

例子:

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 回答
0

当您尝试同步多个线程时,它们必须基于相同的对象引用/实例进行同步。这确保了它们都基于相同的数据同时同步。

希望这有点道理;您只需要基于最终变量而不是动态变量进行同步。

如果方法修改了静态字段,则必须同步对该字段的访问,即使该方法通常仅由单个线程使用。客户端不可能在这种方法上执行外部同步,因为不能保证不相关的客户端也会这样做,请参阅

于 2012-07-13T20:54:28.610 回答