我知道volatile允许可见性,AtomicInteger允许原子性。因此,如果我使用易失性AtomicInteger,这是否意味着我不必再使用任何同步机制?
例如:
class A {
private volatile AtomicInteger count;
void someMethod(){
// do something
if(count.get() < 10) {
count.incrementAndGet();
}
}这是threadsafe吗?
发布于 2013-01-15 21:19:08
我相信Atomic*实际上同时提供了原子性和易失性。因此,当您调用(比方说) AtomicInteger.get()时,您肯定会得到最新的值。java.util.concurrent.atomic package documentation中记录了这一点
原子的访问和更新的内存效应通常遵循挥发的规则,如
™语言规范的第17.4节所述。
现在,如果你有
volatile AtomicInteger count;volatile部分意味着每个线程都将使用最新的AtomicInteger引用,而它是一个AtomicInteger这一事实意味着您还将看到该对象的最新值。
这是不常见的(输入法)需要它-因为通常你不会重新分配count来引用不同的对象。取而代之的是,你需要:
private final AtomicInteger count = new AtomicInteger();在这一点上,它是一个final变量的事实意味着所有线程将处理相同的对象-而它是一个Atomic*对象的事实意味着它们将在该对象中看到最新的值。
发布于 2014-08-30 14:45:17
如果你将线程安全定义为在单线程模式和多线程模式下具有相同的结果,我会说不,它不是线程安全的。在单线程模式下,计数永远不会大于10,但在多线程模式下可以。
问题是get和incrementAndGet是原子的,而if不是。请记住,非原子操作可以在任何时候暂停。例如:
count = 9 currently.if(count.get() <10)并获取true,停止there.true并获取true,因此它运行count.incrementAndGet()并结束。现在count = 10.count.incrementAndGet(),现在运行count = 11,这在单线程模式下永远不会发生。如果你想在不使用更慢的synchronized的情况下让它成为线程安全的,可以尝试这个实现:
class A{
final AtomicInteger count;
void someMethod(){
// do something
if(count.getAndIncrement() <10){
// safe now
} else count.getAndDecrement(); // rollback so this thread did nothing to count
}发布于 2014-12-02 21:03:35
要保持原始语义,并支持多线程,您可以执行以下操作:
public class A {
private AtomicInteger count = new AtomicInteger(0);
public void someMethod() {
int i = count.get();
while (i < 10 && !count.compareAndSet(i, i + 1)) {
i = count.get();
}
}
}这避免了任何线程看到count达到10。
https://stackoverflow.com/questions/14338533
复制相似问题