为什么线程在不同的run方法体上表现不同?

Spa*_*tan 5 java multithreading synchronization volatile

此代码来自Effective Java(Item 66):(没有sync或volatile,这永远不会结束)

public class ThreadPractice {
static boolean canrunstatic;

public static void main(String[] args) throws InterruptedException {

    Thread backgroundThread = new Thread(new Runnable() {
        public void run() {
            int i = 0;
            while (!canrunstatic){i++;}
            System.out.println("finished");
        }
    });
    backgroundThread.start();
    TimeUnit.SECONDS.sleep(1);
    canrunstatic = true;
}
Run Code Online (Sandbox Code Playgroud)

正如布洛赫在该章中提到的那样,它永远不会在控制台上写"完成".我一直在玩这个类,并将该行添加到runnable run方法:

System.out.println("im still running");
Run Code Online (Sandbox Code Playgroud)

有了这个,while循环不仅增加i,而且在每个循环中打印出这个字符串.但是什么让我发疯,这样线程在1秒后停止,当主线程从睡眠状态恢复时.

修改:(停止没有volatile/sync)

public class ThreadPractice {
static boolean canrunstatic;


public static void main(String[] args) throws InterruptedException {

    Thread backgroundThread = new Thread(new Runnable() {
        public void run() {
            int i = 0;
            while (!canrunstatic){i++;System.out.println("im still running");}
            System.out.println("finished");
        }
    });
    backgroundThread.start();
    TimeUnit.SECONDS.sleep(1);
    canrunstatic = true;


}
Run Code Online (Sandbox Code Playgroud)

那么这背后的逻辑是什么?

Min*_*ock 3

准确地说,只是不能保证线程永远停止,但并不禁止它确实停止。这背后的逻辑由Java 内存模型提供,这是一个相当复杂的主题,但需要理解 Java 中的多线程。

这个概念是,如果这两个操作彼此同步,则仅需要另一个线程才能看到对一个线程的非易失性字段的写入。如果执行线程所表现出的行为没有改变,则允许编译器重新排序某些操作。但另一个线程可能会看到这一点。因此,您需要适当的同步来告诉编译器某些部分不允许重新排序。

请在此处阅读有关此内容的完整论文:JSR-133