繁体   English   中英

调用方法后暂停线程

[英]Pause Thread after a method is called

基本上,我想在调用方法后暂停线程,然后再继续执行另一个方法。 我无法循环,我的方法只能运行一次。 其背后的想法是在游戏中使用,该方法将显示消息,并且每当用户按下一个键时,就会显示下一条消息。 我不能只浏览列表,因为游戏需要用户输入。 我看了看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;
}

查看我的修改,看看它是否与您要实现的内容相似。 我正在使用扫描仪来模拟用户输入,只需按键盘上的Enter即可尝试。 顺便说一句,我希望这只是一种锻炼,而不是现实生活中的情况。 除非确实有必要,否则您应尝试避免在实际产品中进行这种低级别的多线程管理,在这种情况下,您仍应使用为此目的使用的适当数据结构。 在实际的应用程序中,按钮将链接到回调,并且您将设置一些onClick()方法以在按下按钮后立即执行所需的代码。

关于并发,我强烈建议您看一下这些教程: Oracle-Concurrency

PS:请注意,我完全忽略了中断,这是一种不好的做法,应该以正确的方式处理这些异常:我只是试图通过使代码尽可能简单来实现所需的结果。 另外,就像其他人指出的那样,您应该通过在循环内调用wait来处理虚假唤醒。

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

文档中所述 ,Object.wait的第一条规则是必须在循环中调用该规则,该循环取决于等待的基础条件。

因此,您的等待需要看起来像这样:

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易变,因为同步已经确保了多线程的一致性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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