假设我有一个从另一个线程更新的 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/