java:在ESC上停止线程

时间:2011-03-30 21:13:42

标签: java multithreading

我正在用Java编写一个简单的游戏,我有以下问题:

我有一个名为MainGameFrame的控制类,其中有一个初始化gameThreadMainGameFrame具有 Esc 键的关键侦听器,因此它会暂停/恢复gameThread。但是,这不起作用:

public void keyPressed(KeyEvent e) {
    // pause the game
    synchronized(gameThread) {
        if(e.getKeyCode() == e.VK_ESCAPE) {
            try {
                if(gameThread.getState() == Thread.State.WAITING) {
                    System.out.println("continue");
                    gameThread.notify();
                    System.out.println("after continue");
                } else {
                    System.out.println("pause");
                    gameThread.wait();
                    System.out.println("after pause");
                }
            } catch (InterruptedException ex) {
                    Logger.getLogger(MainGameFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

它会在 Esc 上暂停并输出“暂停”,但不会“暂停后”。

3 个答案:

答案 0 :(得分:1)

gameThread.wait()不会使gameThread线程暂停。它使当前线程(即事件调度线程)等待。由于EDT正在等待,它不再能够接收到一个按键事件:整个GUI冻结

阅读有关并发的Java教程,特别是以下页面:http://download.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

您应该更改AtomicBoolean变量的值,游戏线程会定期检查该变量是否必须暂停。然后游戏线程将在共享锁对象上等待。恢复时,再次更改布尔变量并通知游戏线程。

答案 1 :(得分:0)

等待另一个线程调用notify()。你不这样做,所以“暂停后”永远不会打印出来。

你想用gameThread.wait()做什么?

答案 2 :(得分:0)

你有等待的想法并向后通知。

一个线程无法直接暂停或杀死另一个线程。但是,您可以更改线程之间共享的变量。当感兴趣的线程看到变量已经改变时,它可能会“暂停”自己。

private static volatile boolean paused = false;
private static ReentrantLock pauseLock = new ReentrantLock();
private static Condition unpaused = pauseLock.newCondition();
public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                if (!paused)
                    paused = true;
                else {
                    pauseLock.lock();
                    try {
                        paused = false;
                        unpaused.signal();
                    } finally {
                        pauseLock.unlock();
                    }
                }
            }
        }
    });
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel panel = new JPanel();
    panel.setPreferredSize(new Dimension(200,200));
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);

    Thread gameThread = new Thread() {
        public void run() {
            while (true) {
                System.out.println("running");
                // presumably the game rendering loop
                if (paused) {
                    pauseLock.lock();
                    try {
                        try {
                            unpaused.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } finally {
                        pauseLock.unlock();
                    }
                }
            }
        }
    };
    gameThread.start();
}

我也会避免使用wait并直接通知,因为在使用wait& amp;时必须注意一些注意事项。 notify(例如你正在等待的线程实际上必须在循环内等待,因为它可以被唤醒而不会被调用)。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4308396

如果不使用同步块,您还应该确保始终以下列模式获取和释放锁:

l.lock();
try {
  // code
} finally {
  l.unlock();
}

http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html

我还建议阅读: http://www.javaconcurrencyinpractice.com/ 在Java中进行并发编程时,存在比您想象的更多的陷阱。

无法从另一个线程暂停或终止线程的原因是执行暂停或终止的线程不知道另一个线程在执行的位置以及另一个线程可能拥有的资源。

如果线程A暂停线程B并且线程B碰巧拥有线程A稍后需要的多个资源,会发生什么?如果线程A杀死线程B而线程B正在使用它应该进行一些特殊清理的资源会发生什么?