java - final 字段的线程安全

标签 java multithreading thread-safety

假设我有一个从另一个线程更新的 JavaBean User,如下所示:

public class A {

    private final User user;

    public A(User user) {
        this.user = user;
    }

    public void aMethod() {
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                ...a long running task..
                user.setSomething(something);
            }

        });
        t.start();
        t.join();
    }

    public void anotherMethod() {
        GUIHandler.showOnGuiSomehow(user);
    }
}

这段代码线程安全吗?我的意思是,当创建 A 实例并调用 A.aMethod 的线程读取用户字段时,它是否看到用户处于新鲜状态?如何以适当的线程安全方式做到这一点?

请注意,我不能修改用户类,我也不知道它本身是否是线程安全的。

最佳答案

Is this code thread safe? ... does it see user in the fresh state?

不是特别重要——user 在你的代码中是 final 的事实对线程安全几乎没有影响,除了它不能被替换这一事实。

应该改变的位是由 setSomething 设置的实例变量。它应该被标记为 volatile

class User {
  // Marked `volatile` to ensure all writes are visible to other threads.
  volatile String something;

  public void setSomething(String something) {
    this.something = something;
  }

}

但是,如果(如您建议的那样)您无权访问 User 类,则必须执行创建内存屏障的同步。在最简单的形式中,您可以将对 user 的访问权限包含在 synchronized 访问权限中。

synchronized (user) {
  user.setSomething(something);
}

添加:- 事实证明(参见 here)实际上可以这样完成:

volatile int barrier = 0;
...
user.setSomething(something);
// Forces **all** cached variable to be flushed.
barrier += 1;

关于java - final 字段的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16709185/

相关文章:

java - 分离对象中的 Hibernate 延迟加载

java - 为什么 Kotlin 中的 `as` 在这种情况下没有转换

java - 使用 Runnable VS 的单个实例创建多个线程。每个线程都有单独的实例

c++ - Qt UIThreadWidget

.net - DataRow线程安全吗?如何使用多个线程更新数据表中的单个数据行? -.net 2.0

java - 反转字符串变量

java - 手动调用PlayFramework自定义错误页面

multithreading - 在 Perl 线程中调用 system() 时产生僵尸进程

iphone - 主线程的 NSRunLoop 在辅助线程中被引用

c# - 这个 BlockingQueue 线程安全吗?