英文:
Wait until infinite while loop is completed
问题
以下是翻译好的部分:
为什么setTestString
方法没有等待?我做错了什么?
英文:
I have an infinite while loop which runs on another thread. In this while loop, I am using a String. For this String, I also have a setter. When someone calls the setter, I want it to wait until the current iteration of the while loop finished and change it for the next iteration.
This is what I tried:
import java.util.concurrent.TimeUnit;
public class Test {
private String testString = "aaaaaaa";
private Test() {
new Thread(() -> {
while (true) {
synchronized (testString) {
System.out.println(testString);
// Simulating a thread blocking operation
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println(testString);
}
}
}).start();
}
private void setTestString(String testString) {
synchronized (testString) {
this.testString = testString;
}
}
public static void main(String[] args) {
Test test = new Test();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
test.setTestString("bbbbbbbb");
}
}
Expected output:
aaaaaaa
aaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
...
Actual output:
aaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
...
Why is not the setTestString
method waiting? What am I doing wrong?
答案1
得分: 1
问题在于你的线程每次都在读取更新后的实例变量。如果你希望循环的迭代看到一致的值,应该只读取实例变量的值一次。另外,由于你从一个线程写入它并从另一个线程读取它,你需要将它声明为volatile
或者在同步方法内进行读写。
private volatile String testString = "aaaaaaa";
private Test() {
new Thread(() -> {
while (true) {
// volatile read
String localTestString = testString;
System.out.println(localTestString);
// 模拟线程阻塞操作
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println(localTestString);
}
}).start();
}
> 当有人调用setter时,我希望它等待当前循环迭代完成
这不是一个好的解决方案。如果你让`set`方法等待,不能保证它会在当前循环迭代完成后被调度。你可以自己看到这一点:将`set`方法更改为:
```java
private void setTestString(String testString) {
synchronized (this.testString) {
this.testString = testString;
}
}
英文:
The problem is that your thread is reading the updated instance variable every time. If you want the iteration of the loop see a consistent value, you should read the value of the instance variable only once. Also, since you are writing it from one thread and reading it from another, you need to make it volatile or do the read-write within synchronized methods.
private volatile String testString = "aaaaaaa";
private Test() {
new Thread(() -> {
while (true) {
// volatile read
String localTestString = testString;
System.out.println(localTestString);
// Simulating a thread blocking operation
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println(localTestString);
}
}).start();
}
> When someone calls the setter, I want it to wait until the current iteration of the while loop finished
That is not a good solution. If you make the set method wait, there is no guarantee it gets scheduled after the current iteration of the loop is finished. You can see it for yourself: change the set method to
private void setTestString(String testString) {
synchronized (this.testString) {
this.testString = testString;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论