[英]DelayQueue unexpected behavior. DrainTo deletes from the queue only 1 expired item
[英]Unexpected thread behavior. Visibility
我有以下代码:
public static boolean turn = true;
public static void main(String[] args) {
Runnable r1 = new Runnable() {
public void run() {
while (true) {
while (turn) {
System.out.print("a");
turn = false;
}
}
}
};
Runnable r2 = new Runnable() {
public void run() {
while (true) {
while (!turn) {
System.out.print("b");
turn = true;
}
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
在课堂上,我们了解了使用非同步代码时可能发生的“可见性”问题。 我知道,为了节省时间,编译器将为循环决定对CPU缓存的抓取turn
,这意味着线程不会知道RAM中的turn
值是否已更改,因为他不检查它。
据我了解,我希望代码像这样运行:
T1将看到转为true->进入循环并打印->将转为false->被卡住
T2会认为转弯没有改变->会被卡住
我希望如果T1在T2之前开始:只会打印'a',并且两个线程都将在无限循环中运行而无需打印其他任何内容
但是,当我运行代码时,有时我会在两个线程卡住之前得到一些“ abab ....”。
我想念什么?
编辑:
以下代码完成了我所期望的:线程将在无限循环中运行:
public class Test extends Thread {
boolean keepRunning = true;
public void run() {
long count = 0;
while (keepRunning) {
count++;
}
System.out.println("Thread terminated." + count);
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
t.start();
Thread.sleep(1000);
t.keepRunning = false;
System.out.println("keepRunning set to false.");
}
}
它们彼此之间有何不同?
当我运行代码时,有时我会在两个线程卡住之前得到一些“ abab ....”。
我怀疑正在发生的事情是,在对代码进行JIT编译时,行为正在改变。 在JIT编译之前,写操作是可见的,因为解释器正在执行写操作。 在JIT编译之后,缓存刷新或读取已被优化……因为内存模型允许这样做。
我想念什么?
您缺少的是您期望未指定的行为是一致的。 不一定是。 毕竟,它是未指定的! (这是正确的,即使我上面提出的解释不正确。)
turn
不是不稳定的事实并不意味着您的代码会中断,而可能会中断。 就我们所知,线程在任何给定时刻都可能看到false或true。 无需特别说明,就可以随意清除缓存,线程可以保留其缓存等。
这可能是因为您的代码正在遭受System.out.print
副作用,该副作用在内部写入同步方法:
521 private void write(String s) {
522 try {
523 synchronized (this) {
( 资料来源-DocJar )
同步的内存影响可能会刷新缓存,因此会影响您的代码。
正如@Stephen C所说,它也可能是JIT,它可能会进行布尔检查,因为它假定值不会由于另一个线程而改变。
因此,在到目前为止提到的三种不同的可能性中,它们都可能是影响代码行为的因素。 可见性是一个因素,而不是决定因素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.