最终场的线程安全性

Beh*_*nil 5 java multithreading thread-safety

假设我有一个JavaBean 用户,它从另一个线程更新,如下所示:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

请注意,我无法修改用户类,我不知道它本身是否是线程安全的.

Old*_*eon 4

这段代码线程安全吗?...它是否看到用户处于新鲜状态?

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;
  }

}
Run Code Online (Sandbox Code Playgroud)

但是,如果(如您所建议的)您无权访问该类User,则必须执行创建内存屏障的同步。在最简单的形式中,您可以使用user一个访问来包围您对 的synchronized访问。

synchronized (user) {
  user.setSomething(something);
}
Run Code Online (Sandbox Code Playgroud)

添加:-事实证明(请参阅此处)实际上可以这样完成:

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