为什么线程在不同的 运行 方法体中表现不同?
Why do thread behave different with different run method body?
此代码来自 Effective Java(第 66 项):(没有同步或易失性,这永远不会结束)
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;
}
正如 Bloch 在该章中提到的那样,它永远不会将 "finished" 写入控制台。我一直在玩这个 class,并将该行添加到 运行nable 运行 方法:
System.out.println("im still running");
有了这个,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;
}
那么这背后的逻辑是什么?
向控制台写入数据通常是线程安全操作。
在这种情况下,您将数据写入控制台的行为也可以触发 canrunstatic
变量的更新,如您的 backgroundThread
所见。
请注意,Java 内存模型和 java System.out
的实现均未承诺这一点
准确地说,只是不保证线程会停止,但不禁止它确实会停止。这背后的逻辑由 Java Memory Model 提供,这是一个相当复杂的主题,但是为了理解 Java.
中的多线程需要。
这个概念是,如果这两个操作彼此同步,则仅需要另一个线程才能看到对一个线程的非易失性字段的写入。如果执行它的线程表现出的行为没有改变,则允许编译器对某些操作重新排序。但是另一个线程可能会看到这个。所以你需要适当的同步来告诉编译器某些部分不允许重新排序。
在此处阅读有关此内容的完整论文:JSR-133
此代码来自 Effective Java(第 66 项):(没有同步或易失性,这永远不会结束)
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;
}
正如 Bloch 在该章中提到的那样,它永远不会将 "finished" 写入控制台。我一直在玩这个 class,并将该行添加到 运行nable 运行 方法:
System.out.println("im still running");
有了这个,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;
}
那么这背后的逻辑是什么?
向控制台写入数据通常是线程安全操作。
在这种情况下,您将数据写入控制台的行为也可以触发 canrunstatic
变量的更新,如您的 backgroundThread
所见。
请注意,Java 内存模型和 java System.out
准确地说,只是不保证线程会停止,但不禁止它确实会停止。这背后的逻辑由 Java Memory Model 提供,这是一个相当复杂的主题,但是为了理解 Java.
中的多线程需要。这个概念是,如果这两个操作彼此同步,则仅需要另一个线程才能看到对一个线程的非易失性字段的写入。如果执行它的线程表现出的行为没有改变,则允许编译器对某些操作重新排序。但是另一个线程可能会看到这个。所以你需要适当的同步来告诉编译器某些部分不允许重新排序。
在此处阅读有关此内容的完整论文:JSR-133