我知道像 i++
这样的复合操作不是线程安全的,因为它们涉及 多个 操作。
但是检查引用本身是线程安全的操作吗?
a != a //is this thread-safe
我尝试对此进行编程并使用多个线程,但没有失败。我想我无法在我的机器上模拟比赛。
编辑:
public class TestThreadSafety {
private Object a = new Object();
public static void main(String[] args) {
final TestThreadSafety instance = new TestThreadSafety();
Thread testingReferenceThread = new Thread(new Runnable() {
@Override
public void run() {
long countOfIterations = 0L;
while(true){
boolean flag = instance.a != instance.a;
if(flag)
System.out.println(countOfIterations + ":" + flag);
countOfIterations++;
}
}
});
Thread updatingReferenceThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
instance.a = new Object();
}
}
});
testingReferenceThread.start();
updatingReferenceThread.start();
}
}
这是我用来测试线程安全的程序。
奇怪的行为
当我的程序在一些迭代之间启动时,我得到了输出标志值,这意味着引用 !=
对同一引用的检查失败。但是经过一些迭代后,输出变为常量值false
,然后长时间执行程序不会生成单个true
输出。
正如输出所暗示的,经过一些 n(非固定)迭代后,输出似乎是恒定值并且不会改变。
输出:
对于一些迭代:
1494:true
1495:true
1496:true
19970:true
19972:true
19974:true
//after this there is not a single instance when the condition becomes true
最佳答案
在没有同步的情况下这段代码
Object a;
public boolean test() {
return a != a;
}
可能会产生 true
。这是 test()
ALOAD 0
GETFIELD test/Test1.a : Ljava/lang/Object;
ALOAD 0
GETFIELD test/Test1.a : Ljava/lang/Object;
IF_ACMPEQ L1
...
正如我们所看到的,它将字段 a
加载到本地变量两次,这是一个非原子操作,如果 a
在两者之间被另一个线程更改,则比较可能会产生 假
。
此外,内存可见性问题与此处有关,不能保证另一个线程对 a
所做的更改将对当前线程可见。
关于java - != 检查线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18460580/