public class Main {
public static void main(String[] args) throws InterruptedException {
Worker w = new Worker();
w.start();
sleepQuietly(1000);
w.alive = false;
w.join();
}
static class Worker extends Thread {
boolean alive = true;
@Override
public void run() {
while (alive) {
}
}
}
static void sleepQuietly(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果我运行上面的main方法,主线程将不会停止。但是如果我运行下面的main方法,main方法将停止。
public class Main {
public static void main(String[] args) throws InterruptedException {
Worker w = new Worker();
w.start();
sleepQuietly(1000);
w.alive = false;
w.join();
}
static class Worker extends Thread {
boolean alive = true;
@Override
public void run() {
while (alive) {
sleepQuietly(1);
}
}
}
static void sleepQuietly(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
“内存模型保证,在最终发生上述操作的情况下,对一个线程所做的特定字段的特定更新最终会被另一个线程看到。但最终可能是一个任意长的时间。长时间的代码在不使用同步的线程中,与其他线程相关的字段值无可救药。特别是,编写循环等待其他线程写入的值总是错误的,除非字段是易失性的或通过同步“< / p>
我在http://gee.cs.oswego.edu/dl/cpj/jmm.html上面阅读过,这是我的问题: 1.在第一个示例中,为什么工作线程无法看到主线程更新的值,因为JMM保证一个线程对特定字段的特定更新最终会对另一个线程可见
答案 0 :(得分:4)
JMM保证对特定字段的特定更新 一个线程最终将对另一个
可见
它仅在某些条件下保证(最终)可见性。您所指的链接明确说明了这一点。写入非易失性字段不属于这种情况。
为什么Thread.sleep()有所不同?
Thread.sleep()
是一种未被JIT内联的本机方法。调用此方法会中断loop invariant hosting优化,因此每次迭代都会重新读取对象字段。但是,此行为是特定JVM的实现细节。无法保证程序在其他版本的JVM上的行为方式相同。此外,JLS明确warns,Thread.sleep
和Thread.yield
都没有任何同步语义。
答案 1 :(得分:1)
看看:https://help.semmle.com/wiki/display/JAVA/Spin+on+field
class Spin {
public boolean done = false;
public void spin() {
while(!done){
}
}
}
class Spin { // optimized
public boolean done = false;
public void spin() {
boolean cond = done;
while(!cond){
}
}
}
该方法重复while循环,直到完成字段的值由另一个线程设置。但是,编译器可以优化代码,如第二个代码片段所示,因为完成的字段没有标记为volatile,并且循环体中没有可以更改done值的语句。优化版本的自旋循环,即使另一个线程设置为true。