简体   繁体   中英

Pause Thread after a method is called

Basically I want to pause my Thread after I called a method, before continuing to the other one. I can't loop, my method can only be ran once. The idea behind this, is to be used in a game, where the methods will display messages, and each time a user presses a key, the next message sould be shown. I can't just go through a list, as the game takes input from the user. I looket at Thread.pause() and Thread.resume() but they woN't work either, and are deprecated. My current code (Which isn't working):

private Thread thread;
private Thread managerThread;
private final Object lock = new Object();

private boolean shouldThreadRun = true;
private boolean storyRunning = true;

public Storyline() {
    setUpThread();
}

private void setUpThread() {
    managerThread = new Thread(() -> {
        while(storyRunning) {
            synchronized (lock) {
                if(!shouldThreadRun) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Looping");
            }
        }
    });
    thread = new Thread(() -> {
        synchronized (lock) {
            pauseThread();
            System.out.print("A");
            pauseThread();
            System.out.print("B");
        }
    });
    managerThread.start();
    thread.start();
}

public void pauseThread() {
    shouldThreadRun = false;
}
public void resumeThread() {
    shouldThreadRun = true;
}

Take a look at my edits and see if it is any similar to what you were trying to achieve. I'm using a scanner to simulate user input, just press enter on your keyboard to try it out. By the way I hope this is just an exercise and not a real life situation. You should try to avoid this kind of low level management of multithreading in a real product, unless really necessary, in which case you should still use appropriate data structures meant for this. In a real application buttons will be linked to callbacks and you will set some onClick() method to execute the code you need, as soon as the button is pressed.

For what concerns concurrency, I strongly suggest you to take a look at these tutorials: Oracle-Concurrency

PS: notice that I'm completely ignoring interrupts, which is a bad practice, those exception should be handled the right way: I was just trying to achieve the desired result by keeping the code as simple as possible. Also, like someone else pointed out, you should handle spurious wakeups by just calling the wait inside a loop.

private Thread thread;
private Thread managerThread;
private final Object lock = new Object();

Scanner in;

public Storyline() {
    setUpThread();
}

private void setUpThread() {
    managerThread = new Thread(() -> {
        while(true) {
            in = new Scanner(System.in);
            in.nextLine();
            resumeThread(); 
        }
    });
    thread = new Thread(() -> {
        synchronized (lock) {
            while(true){
                System.out.print("A");
                try {
                    lock.wait();
                } catch (InterruptedException e) {}
                System.out.print("B");
                try {
                    lock.wait();
                } catch (InterruptedException e) {}
            }
        }
    });
    managerThread.start();
    thread.start();
}


public void resumeThread() {
    synchronized(lock){
        lock.notify();
    }
}

The first rule of Object.wait, as described in the documentation , is that it must be called in a loop which depends on the condition which is the basis for the wait.

So, your wait needs to look like this:

synchronized (lock) {
    while (!shouldThreadRun) {
        lock.wait();
    }
}

An interrupt is not something that happens by accident. A thread is only interrupted if another thread explicitly asks it to stop what it's doing and exit cleanly.

Therefore, if you get an interrupt, the correct course of action is not to ignore it and print a stack trace. You need to exit cleanly.

The easiest way to do this is to simply enclose your entire while loop in a try/catch:

try {
    while (storyRunning) {
        synchronized (lock) {
            while (!shouldThreadRun) {
                lock.wait();
            }
            System.out.println("Looping");
        }
    }
} catch (InterruptedException e) {
    System.out.println("Exiting, because someone asked me to stop.");
    e.printStackTrace();
}

This way, your while-loop will automatically exit when interrupted.

Lastly, Object.wait is useless unless another thread calls Object.notify or Object.notifyAll on the very same object on which the waiting thread is synchronized. The wait method will (probably) never return unless the object gets a notify:

public void pauseThread() {
    synchronized (lock) {
        shouldThreadRun = false;
        // Tell waiting thread that shouldThreadRun may have changed.
        lock.notify();
    }
}

public void resumeThread() {
    synchronized (lock) {
        shouldThreadRun = true;
        // Tell waiting thread that shouldThreadRun may have changed.
        lock.notify();
    }
}

Notice that the synchronizing is inside the methods. If you keep your thread synchronized on lock all the time, the manager thread will never have a chance to run at all, because it's trying to acquire a synchronization lock on the same object. (However, the opposite is not true; the manager thread can stay synchronized on lock all the time, because the wait() method will temporarily release the synchronization lock, allowing the other thread to proceed.)

If all code which accesses shouldThreadRun is inside synchronized blocks, you don't need to (and should not) make shouldThreadRun volatile, since the synchronization already ensures multi-threaded consistency.

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