英文:
Java: For loop in while loop not running unless println statement included
问题
以下是翻译好的部分:
我正在尝试在一个无限的while循环内部运行一个for循环。当没有print语句时,代码不会按预期运行,但是当有print语句时,它可以正常运行。以下是代码:
class Test implements Runnable{
public static int varint = 0;
public static void main(String args[]){
Thread x = new Thread(new Test());
int i;
x.start();
while(true){
System.out.println("Hello World"); // 如果不包括这句话,
// 就不会执行退出语句
for(i=0;i<varint;i++){
System.out.println("Exit");
System.exit(0);
}
}
}
public void run(){
try{
Thread.sleep(5000);
} catch(Exception e){
System.out.println("Caught");
}
varint = 1;
}
}
这只是从一个更大的循环中摘录的一个小例子。我该如何修复这个问题?
英文:
I am trying to run a for loop inside an infinite while loop. The code doesn't run as intended when there's no print statement, but when there is a print statement, it runs fine. Here is the code:
class Test implements Runnable{
public static int varint = 0;
public static void main(String args[]){
Thread x = new Thread(new Test());
int i;
x.start();
while(true){
System.out.println("Hello World"); //If this isn't included,
//the exit statement isn't executed
for(i=0;i<varint;i++){
System.out.println("Exit");
System.exit(0);
}
}
}
public void run(){
try{
Thread.sleep(5000);
} catch(Exception e){
System.out.println("Caught");
}
varint = 1;
}
}
This is just a small example taken from a much bigger loop. How can I fix this?
答案1
得分: 7
你的代码存在数据竞争。其中一个线程写入了 varint
,而另一个线程在没有明确同步的情况下读取了 varint
。varint
没有声明为 volatile
。根据Java内存模型,不能保证读取线程能够看到 varint
的变化。
当你添加了 println
后代码可以工作,因为 println
在内部使用了同步,这使得 varint
对运行中的线程可见。
要么使用锁来读写 varint
,要么将其声明为 volatile
。
以下是关于Java内存模型和volatile的良好资源:
http://tutorials.jenkov.com/java-concurrency/java-memory-model.html#visibility-of-shared-objects
英文:
You have a data race. One of the threads write to varint
and the other reads varint
with no explicit synchronization. varint
is not declared volatile. According to Java memory model, there is no guarantee the reading thread will ever see the that varint
was changed.
It works when you add the println
because println uses synchronization internally, which makes varint
visible to the running thread.
Either use a locking to read/write varint
, or declare it volatile
.
This is a good source for the Java memory model and volatiles:
http://tutorials.jenkov.com/java-concurrency/java-memory-model.html#visibility-of-shared-objects
答案2
得分: 1
在这个仿真中执行循环的主线程不能保证看到对 varint
的任何更新。因此,varint
可能会被更新为 1 或 100,但主线程仍然无法保证能够看到这些更新。
为了保证内存可见性,请使用 volatile
或同步原语。
请参考来自 Java 5 并发架构师的以下链接。该文章解释了:“状态标志和 volatile”。
另一方面,在某些情况下(就像您的情况中添加打印时一样),读取线程可能会偶尔看到更新,并且程序似乎表现正常。如果此类可见性问题出现在生产环境中,追踪起来会非常困难。
英文:
The main thread executing the loop in this avatar is not guaranteed to see any updates to varint
. So varint
can be updated to 1 or 100 but there would still be no guarantees for main thread to be able to see the updates.
In order to guarantee memory visibility, use a volatile or synchronization primitives.
Please see the following link from an architect of Java 5 Concurrency. This article explains: "Status Flags and Volatile"
On the other hand, the reading thread in certain cases (intermittently as in your case when you add the print) might see the update and it might seem the program is behaving correctly. Such kind of visibility issues are extremely hard to track if it makes it to production.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论