考虑下面的代码,我想让它成为一个线程安全的类,这样它就永远不会得到奇数:
class Test {
private int value = 0;
private final Object lock;
public void add() {
synchronized (lock) {
value++;
value++;
}
}
public int getValue() {
synchronized (lock) {
return value;
}
}
}
我现在怀疑锁定字段,这被宣布为最终的,这有关系吗?或者它会打破线程的安全吗?
我认为如果未将lock字段声明为final,那么这应该是一个线程安全的类。如果这个结论有误,请指正,谢谢。
答案 0 :(得分:9)
我现在怀疑锁定字段,它被宣布为最终的,这有关系吗?
是的,它被认为是仅锁定final
字段对象的最佳做法。
如果您可以更改引用,则可以更改锁定的对象,从而破坏线程安全。
答案 1 :(得分:1)
应该没问题。甚至可能使它更安全,因为在执行期间不能简单地将其他东西分配给锁。
答案 2 :(得分:1)
您可以使用ReadWriteLock实现相同的结果并实现安全。
参考文献:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html
答案 3 :(得分:1)
如果你想锁定一个实例,那么final是可以接受的。如果您想在类上锁定或放置互斥锁,请将变量设置为静态。
答案 4 :(得分:0)
在Java中,同步由锁定对象的某个隐藏字段完成。最后的意思是,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
答案 5 :(得分:0)
当您尝试同步多个线程时,必须根据相同的对象引用/实例对它们进行同步。这可以确保它们根据相同的数据同时进行同步。
希望这有点意义;你只需要根据最终变量而不是动态变量进行同步。
如果方法修改静态字段,则必须同步访问权限 此字段,即使该方法通常仅由单个使用 线。客户端无法执行外部操作 这种方法同步因为无法保证 不相关的客户也会这样做,see。