原子变量能保证内存可见性吗?

时间:2017-03-17 22:39:08

标签: java multithreading concurrency atomicity memory-visibility

关于内存可见性的小问题。

CodeSample1:

class CustomLock {

    private boolean locked = false;

    public boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

这个代码在多线程环境中容易出错,首先是因为" if-then-act"这不是原子的,其次是因为潜在的内存可见性问题,例如threadA将字段设置为true,但后来希望读取字段值的threadB可能看不到,并且仍然看到值false。 / p>

最简单的解决方案是使用synchronized关键字,如CodeSample2。

CodeSample2:

class CustomLock {

    private boolean locked = false;

    public synchronized boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

现在如果我想使用原子变量怎么办?例如,AtomicBoolean(问题适用于所有原子变量),

CodeSample3:

   public static class CustomLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public boolean lock() {
        return locked.compareAndSet(false, true);
    }
}

除了更好的性能考虑之外,我们可以看到,现在我们已经实现了类似于" if-then-act"来自 CodeSample1 ,使用AtomicBoolean。 代码在逻辑上的作用并不重要, 我的问题是 如果2个线程调用 CodeSample3中的lock()方法强大>大约在同一时间,虽然很明显现在对该字段的任何写操作都将以原子方式完成,但使用AtomicBoolean是否也能保证内存可见性?

很抱歉这个故事很长,只是想确保我尽可能清楚地表达,谢谢你们......

2 个答案:

答案 0 :(得分:5)

是的,根据javadocs it guarantees

  

compareAndSet和所有其他读取和更新操作(如getAndIncrement)都具有读取和写入volatile变量的内存效果。

答案 1 :(得分:0)

  

我遇到的问题是,如果2个线程在同一时间内调用CodeSample3中的lock()方法,同时它清楚地表明对该字段的任何写操作现在将以原子方式完成,是否使用AtomicBoolean还保证了内存可见性吗?

要使AtomicBoolean同时处理来自不同线程的多个操作,具有以保证内存可见性。它可以保证,因为它包含volatile字段。它是volatile的语言语义,它确保跨越内存障碍,以便多个线程看到最新的值,并且任何更新都将发布到主内存。

顺便说一句,您的lock(...)方法应准备好tryLock(...),因为它可能无法锁定。