【问题标题】:Stopping and resuming infinite loop on key input在按键输入上停止和恢复无限循环
【发布时间】:2015-02-04 18:57:23
【问题描述】:

假设我们有一个无限循环,我们想让它休眠一段时间,然后再恢复它。我们没有设定时间,而是在按下一个键时恢复它。

例如,在 Java 中我们可以:

while(true){
    doSomething();
}

现在,我们可以通过多种方式使其可中断。我们想在按键时中断它,所以我们将:

boolean running = true;
...
this.addKeyListener(this);
...
@override
public void keyPressed(KeyEvent e){
    running = false;
}

然后运行一个方法(比如说run),其中包含:

while(running){
    doSomething();
}

但是我们会遇到一个问题:恢复。

所以我们采用keyPressed 方法,并将其主体更改为:

running = !running;
if(running){
    run();
}

这里只有一个问题:在run 方法完成之前,KeyListener 不会做任何事情。我尝试过使用线程,我们可以:

private class Runner implements Runnable {
    @Override
    public void run() {
        while (running) {
            doSomething();
        }
    }
}

keyPressed:

if(running){
    runner.wait();
}else{
    runner.notify();
    runner.run();
}
running = !running;

但在我的实际代码中,doSomething 方法是不能被中断的代码(因为它处理屏幕的输出),所以永远不能调用 thread.wait()(它会一直抛出异常,实际上不会等等)。

那么,总结一下:如何在 Java 中使用键盘输入随意停止和恢复循环?

【问题讨论】:

  • 你能告诉我们你用线程尝试了什么吗?
  • @Charlie 我更新了帖子以包含该信息
  • 你应该在 keyPressed 中尝试runner.start(),这会产生一个并行线程,让你原来的线程继续运行

标签: java loops input infinite-loop


【解决方案1】:

waitnotify 旨在从不同的线程调用。顾名思义,wait 应该在暂停并等待通知条件已更改的线程中调用:

private final Object keyPressMonitor = new Object();

private boolean running = true;

private Runnable gameLoop = new Runnable() {
    @Override
    public void run() {
        try {
            synchronized (keyPressMonitor) {
                while (true) {
                    while (!running) {
                        keyPressMonitor.wait();
                    }
                    doSomething();
                }
            }
        } catch (InterruptedException e) {
            logger.log(Level.INFO,
                "Interrupted; cleaning up and exiting.", e);
        }
    }
};

另一个线程,大概是调用 KeyListener(或由 ActionMap/InputMap 绑定调用的动作)的 AWT 事件调度线程,将通知循环线程正确的键已被按下或释放:

public void keyPressed(KeyEvent event) {
    if (event.getKeyCode() == theKeyICareAbout) {
        synchronized (keyPressMonitor) {
            running = true;
            keyPressMonitor.notifyAll();
        }
    }
}

public void keyReleased(KeyEvent event) {
    if (event.getKeyCode() == theKeyICareAbout) {
        synchronized (keyPressMonitor) {
            running = false;
            keyPressMonitor.notifyAll();
        }
    }
}

【讨论】:

    【解决方案2】:

    您可以将Semaphore 用于这些目的:

    private static class Runner implements Runnable {
        private final AtomicInteger permits = new AtomicInteger(0);
        private final Semaphore semaphore = new Semaphore(1, true);
        private volatile boolean running;
    
        public void putToSleep() {
            semaphore.acquireUninterruptibly();
        }
    
        public void resume() {
            semaphore.release(permits.getAndSet(0));
        }
    
        @Override
        public void run() {
            while (running) {
                semaphore.acquireUninterruptibly(Integer.MAX_VALUE);
                semaphore.release(Integer.MAX_VALUE);
                doSomething();
            }
        }
    
        private void doSomething() {
            //...
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-24
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      • 2023-03-24
      相关资源
      最近更新 更多