[英]Thread Safety using final
下面是一个解释线程安全的示例方法:
class Counter {
private int counter = 0;
public void increment() {
counter++;
}
public int getValue() {
return counter;
}
}
为了提供线程安全,有几种方法,我更喜欢使用AtomicInteger
方法。 然而;
1.我还想知道是否可以通过对必要的变量使用final
来提供线程安全。 如果是这样,我该如何执行此操作?
2.在 Java 中经常使用final
作为变量和方法 arguments 提供线程安全的原因之一是什么?
我只是将这个添加到 Erwan Daniel 的回答中。
如果您想在所有线程之间共享一个计数器,这里是您的代码的另一个版本。
class SharedCounter {
private AtomicInteger sharedCounter ;
public Counter(){
this.sharedCounter = new AtomicInteger(0);
}
public void increment() {
sharedCounter.getAndIncrement();
}
public int value() {
return sharedCounter.get();
}
最终将阻止您的atomicInteger12
更改它正在使用的object您可以自由设置它的值。
final SharedCounter atomicInteger12 = new Counter() ;
在正确同步的代码中,不需要final。
例如,如果你会使用:
class MyCounter{
private AtomicInteger c = new AtomicInteger();
public int inc(){return c.incrementAndGet();}
public int get(){return c.get();}
}
您将与另一个线程共享“MyCounter”,您需要确保在写入 c 和读取 c 之间存在先发优势。 这可以通过各种方式完成,例如将 MyCounter 实例传递给某个线程的构造函数(线程启动规则)。 或者您通过 volatile 字段(volatile 变量规则)或同步块(监视器锁定规则)传递数据。
这通常称为“安全发布”,对于大多数系统来说,这已经足够了。 如果您没有安全地通过引用,您就会遇到数据竞争,并且可能会发生奇怪的问题。 因此有第二种机制称为初始化安全; 因此,无论对 object 的引用是否未正确发布,使用 final 的初始化安全都将作为备用解决方案。 此 AFAIK 的主要用例是安全性。
所以对于正确同步的代码,不需要final。
这并不意味着你可以忽略它。 它有各种各样的好处,比如没有意外的变化,而且信息量很大。 所以我更喜欢让尽可能多的字段成为final。
从 memory model 的角度来看,Final 对于方法 arguments 没有任何意义,因为它们是线程私有的。 只有共享的 memory 需要在 memory model 中处理。
不, final
关键字与线程安全没有任何共同之处。
变量的final
关键字使它们不可变,您不能再更改它们的值。 但是,它不像 c++ 中的const
关键字,整个变量内容都不能改变。 在 Java 中,只有引用是不可变的。
final AtomicReference<String> toto = new AtomicReference<>("text");
toto.set("new text"); // totally fine
toto = new AtomicReference<>("text"); // does not compile, as toto is immutable reference.
但是,还有另一个关键字可以满足您的需求。 它是volatile
的。 https://www.baeldung.com/java-volatile
简而言之,所有线程上的值同时更改并且立即可用。 这就是所有Atomic*
Java 类中使用的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.