所以我写了一个小程序,它将移动圆圈,当它们发生碰撞时,它们会向相反的方向移动,但是当我试图延迟执行时,他们不会愚蠢地快速移动我得到{ {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
,因此程序崩溃。如何解决这个问题? (或者我在哪里傻?)
答案 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
,可能会更加清晰。