基本上我想在调用方法之后暂停我的线程,然后再继续使用另一个方法。我无法循环,我的方法只能运行一次。
这背后的想法是在游戏中使用,其中方法将显示消息,并且每次用户按下键时,将显示下一个消息。当游戏从用户那里获取输入时,我无法浏览列表。我在Thread.pause()
和Thread.resume()
看了一下,但他们也没有工作,并且已被弃用。
我目前的代码(其中没有工作):
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;
}
答案 0 :(得分:0)
查看我的编辑内容,看看它是否与您尝试实现的内容类似。我正在使用扫描仪模拟用户输入,只需按键盘上的Enter即可试用。 顺便说一句,我希望这只是一个练习,而不是现实生活中的情况。您应该尽量避免在实际产品中使用这种低级别的多线程管理,除非确实有必要,在这种情况下,您仍应使用适合此的数据结构。在实际应用程序中,按钮将链接到回调,并且您将设置一些onClick()方法以在按下按钮时执行所需的代码。
关于并发性的问题,我强烈建议您查看这些教程:Oracle-Concurrency
PS:注意我完全忽略了中断,这是一种不好的做法,这些异常应该以正确的方式处理:我只是试图通过尽可能简化代码来实现预期的结果。此外,就像其他人指出的那样,你应该通过在循环内调用等待来处理虚假的唤醒。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();
}
}
答案 1 :(得分:0)
Object.wait的第一个规则as described in the documentation,是必须在循环中调用,这取决于作为等待基础的条件。
所以,你的等待需要看起来像这样:
synchronized (lock) {
while (!shouldThreadRun) {
lock.wait();
}
}
中断不是意外发生的事情。只有当另一个线程明确要求它停止正在进行的操作并且干净地退出时,线程才会被中断。
因此,如果您收到中断,正确的操作过程是而不是忽略它并打印堆栈跟踪。你需要干净利落地退出。
最简单的方法是简单地将整个while循环包含在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();
}
这样,你的while循环会在中断时自动退出。
最后,除非另一个线程在等待线程同步的同一对象上调用Object.notify或Object.notifyAll,否则Object.wait是无用的。除非对象获得通知,否则wait方法(可能)永远不会返回:
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();
}
}
请注意,同步在方法内部。如果你的线程始终在lock
保持同步,那么管理器线程根本就没有机会运行,因为它试图在同一个对象上获取同步锁。 (但是,相反的情况并非如此;管理器线程可以始终在lock
保持同步,因为wait()方法将暂时释放同步锁,允许其他线程进行。)
如果访问shouldThreadRun
的所有代码都在同步块内,则不需要(也不应该)使shouldThreadRun
为volatile,因为同步已经确保了多线程的一致性。