简体   繁体   中英

Wait until infinite while loop is completed

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?

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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM