Thread什么时候从主内存而不是工作内存中读取非易失性变量?

When does Thread read a non-volatile variable from main memory instead of working memory?

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方法,主线程不会stop.But如果我运行下面的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();
    }
}
}

"The memory model guarantees that, given the eventual occurrence of the above operations, a particular update to a particular field made by one thread will eventually be visible to another. But eventually can be an arbitrarily long time. Long stretches of code in threads that use no synchronization can be hopelessly out of synch with other threads with respect to values of fields. In particular, it is always wrong to write loops waiting for values written by other threads unless the fields are volatile or accessed via synchronization"

我在 http://gee.cs.oswego.edu/dl/cpj/jmm.html 中阅读了上面的内容,这是我的问题: 1. 在第一个例子中,为什么工作线程看不到主线程更新的值,因为 JMM 保证一个线程对特定字段的特定更新最终对另一个线程可见

  1. 为什么 Thread.sleep() 会有所不同?

看看: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){
        }
    }
}

The method repeats the while-loop until the value of the field done is set by another thread. However, the compiler could optimize the code as shown in the second code snippet, because the field done is not marked as volatile and there are no statements in the body of the loop that could change the value of done. The optimized version of spin loops forever, even when another thread would set done to true.

JMM guarantees that a particular update to a particular field made by one thread will eventually be visible to another

它仅在特定条件下保证(最终)可见性。您所指的 link 明确说明了这一点。写入非易失性字段不属于此类条件。

Why does Thread.sleep() makes difference?

Thread.sleep() 是 JIT 未内联的本机方法。调用此方法会中断 loop invariant hosting optimizations, so that object field is re-read each iteration. However, this behavior is an implementation detail of the particular JVM. It is not guaranteed that the program will behave the same way on other versions of JVM. Moreover, JLS explicitly warns Thread.sleepThread.yield 都没有任何同步语义。