java - 并发、对象可见性

标签 java concurrency multithreading volatile

我想弄清楚下面的代码是否存在任何潜在的并发问题。具体来说,与 volatile 变量相关的可见性问题。 Volatile 定义为:此变量的值永远不会在线程本地缓存:所有读取和写入都将直接进入“主内存”

public static void main(String [] args)
{
    Test test = new Test();

    // This will always single threaded
    ExecutorService ex = Executors.newSingleThreadExecutor();

    for (int i=0; i<10; ++i)
        ex.execute(test);
}

private static class Test implements Runnable {
    // non volatile variable in question
    private int state = 0;

    @Override
    public void run() {
        // will we always see updated state value? Will updating state value
        // guarantee future run's see the value?
        if (this.state != -1)
            this.state++;
    }
}

对于上面的单线程执行器:

test.state 不可变可以吗?换句话说,每个连续的 Test.run()(这将按顺序发生而不是同时发生,因为执行程序也是单线程的),总是会看到更新的 test.state 值?如果不是,Test.run() 的退出是否确保本地线程所做的任何更改都被写回主内存?否则,如果不是在线程退出时,本地线程所做的更改何时会写回主内存?

最佳答案

只要它只是一个单线程,就没有必要让它变易变。如果你打算使用多线程,你不仅应该使用 volatile,还应该使用 synchronize。 递增数字不是原子操作 - 这是一个常见的误解。

public void run() {
    synchronize (this) {
        if (this.state != -1)
            this.state++;
    }
}

除了使用同步,您还可以使用 AtomicInteger#getAndIncrement() (如果您之前不需要 if)。

private AtomicInteger state = new AtomicInteger();

public void run() {
    state.getAndIncrement()
}

关于java - 并发、对象可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1901789/

相关文章:

java - 如何结合switch语句和if case?

sql - 为什么缺少主键/唯一键会导致更新插入时出现死锁问题?

.net - RabbitMQ、.NET 和多线程

swift - 为什么在 Mac OS 控制台应用程序中对 runloop.run 的调用方法会创建额外的线程?

java - 自动从json创建java对象?

java - MediaPlayer播放完毕后执行代码?

java - SMS Retriever API - 为应用程序特定的 keystore 文件生成 11 个字符的哈希码

java - 在多线程中使用wait()和notify()

java - 尝试进入同步块(synchronized block)时出现 IllegalStateException

python - 关于 python 中线程输出的困惑