更改ReentrantLock的所有者

时间:2017-03-16 03:19:58

标签: java multithreading

所以我写了一个小程序,它将移动圆圈,当它们发生碰撞时,它们会向相反的方向移动,但是当我试图延迟执行时,他们不会愚蠢地快速移动我得到{ {1}} 锁定canvasRender.java,创建一个实例:

java.lang.IllegalMonitorStateException

暂停执行片刻的方法,因此圈子不会超快地移动。

ReentrantLock renderLock = new ReentrantLock();

然后从我创建窗口的另一个类中添加actionListener

 publlic void delay(){    
        renderLock.unlock();
        try { Thread.sleep(10); } catch (Exception e) {} ;
        renderLock.lock();
    }

在createAndShowGUI()中:

public static void main(String[] args){
//Buttons and other elements
// ...
JButton start = new JButton("Start!");
createAndShowGUI();
}

在这种情况下,我的锁定归static void createAndShowGUI(){ //adding elements to panels start.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { start(); //this will set gameIsRunning variable to true and create models while (gameIsRunning) { //update(); //which has delay(); at the end of frame drawing //but even if just put delay() delay(); //still says exception start.setEnabled(false); //while game is running button is unavailable } start.setEnabled(true); } }); } 所有,但当我点击按钮时,开始!'当前为Thread main,因此程序崩溃。如何解决这个问题? (或者我在哪里傻?)

1 个答案:

答案 0 :(得分:0)

问题是,在renderLock.unlock()调用AWT-EventQueue-0后,您从renderLock.lock()致电main。线程AWT-EventQueue-0不允许调用它unlock(),因为它不是首先调用lock()它的线程。

您可以通过删除ReentrantLock并使用synchronized来简化操作。

我不知道程序其余部分的设计,但在我看来while循环的内容属于一个单独的线程。您通常不希望在UI侦听器方法(例如actionPerformed()中的ActionListener)中循环,因为它会冻结GUI。

您可以做的一件事是添加Object进行同步:

private static final Object LOCK = new Object()

然后将游戏更新逻辑移动到自己的线程 - 类似这样:

private static class GameThread extends Thread {
    public GameThread() {
        super("GameThread");
    }

    public void run() {
        synchronized (LOCK) {
            start();
            while (gameIsRunning) {
                update();
                try {
                    // Try to sleep for 10 millis:
                    LOCK.wait(10);
                } catch (InterruptedException ignored) { }
            }
        }
        // Re-enable the button:
        javax.swing.SwingUtilities.invokeLater(() -> start.setEnabled(true));
    }
}

您可以更改ActionListener只需停用该按钮并启动GameThread

start.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        start.setEnabled(false);
        synchronized(LOCK) {
            if(!gameIsRunning) {
                new GameThread().start();
            }
        }
   }
});

任何其他检查或修改游戏状态的代码也应该包含在synchronized (LOCK)块中。如果update()修改了GUI以及游戏状态,则可能需要SwingUtilities.invokeLater()

start()重命名为setupGame(),将JButton start重命名为JButton startButton,可能会更加清晰。