[英]Java: While loop does not exit
有谁知道为什么只有在出现System.out.println()的情况下才会退出?
如果我将println()注释掉,则完全相同的代码不起作用
do{
System.out.println("");
if(hasWon()){
InOut.out(output() + "\nYou Won");
System.exit(0);
}
} while (!hasWon())
程序如下
static final int gridSize = Integer.parseInt(InOut.in(1, "Enter grid size"));
static Tile[][] board = new Tile[gridSize][gridSize];
static int winCond = 1;
static GuiFrame f = new GuiFrame(gridSize);
static BtnPanel p = new BtnPanel(gridSize);
static JButton[][] btn = new JButton[gridSize][gridSize];
public static void main(String[] args) {
//Creating objects
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
board[i][z] = new Tile();
}
}
GUI();
while (!hasWon()) {
System.out.println("");
if(hasWon()){
InOut.out(output() + "\nYou Won");
System.exit(0);
}
}
}
public static boolean hasWon() {
boolean hasWon = true;
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
hasWon = hasWon && (board[i][z].getStatus() == winCond);
}
}
return hasWon;
}
public static String output() {
String message = "";
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
message += board[i][z].getStatus() + " ";
}
message += "\n";
}
return message;
}
public static void GUI() {
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
String btnValue = "";
btnValue += board[i][z].getStatus();
btn[i][z] = new JButton();
btn[i][z].setText(btnValue);
btn[i][z].addActionListener(f);
p.add(btn[i][z]);
}
}
f.add(p, BorderLayout.CENTER);
}
public static void modifyGUI(int i, int z){
btn[i][z].setText(String.valueOf(board[i][z].getStatus()));
}
这是一个益智游戏,用户单击一个图块,相邻的图块也会发生变化。 但是,当拼图完成时,如果没有println(),则不会显示完成,而对于println(),则将退出循环并退出程序。
重新强调一下,如果while循环中有一个println(),那么一切都会正常工作。 当我注释掉它不起作用。
您所拥有的是一个密集的CPU密集循环,该循环反复调用hasWon()
。 看起来还有些其他线程负责更新板状态,从而导致“获胜”位置。
看起来问题是紧张的CPU循环导致另一个线程饿死,并且插入println
足以允许线程调度程序重新调度。
另一个可能的解释是,您拥有一个线程正在读取而另一个线程正在更新的共享数据结构, 而没有任何同步 。 从理论上讲,您未同步的事实可能意味着更新线程所做的更改永远不会被读取线程看到,因为编译器尚未看到需要插入“屏障”指令的必要,这将导致相关的高速缓存刷新,等等。 。
就像@chrylis指出的那样,这样的繁忙循环效率极低。 您需要做的是替换繁忙的循环:
一个有问题的解决方案是将Thread.sleep()
调用放入循环中(而不是println
调用)。
更好的解决方案是使用Object.wait()
和Object.notify()
。 主线程在每次检查后在互斥对象上调用wait()
,而正在执行更新的线程每次在其互斥对象上执行可能会导致“获胜”的更新时,都会在同一互斥对象上调用notify()
。
第二种解决方案还处理同步问题。 wait()
和notify()
方法只能在保持互斥锁的同时执行。 即以synchronized
块或方法。
以下是一些代码片段,显示了如何实现等待/通知。
public static final Object mutex = new Object();
public static boolean finished = false;
// One thread
synchronized (mutex) {
while (!finished) {
mutex.wait();
}
}
// Another thread
synchronized (mutex) {
finished = true;
mutex.notify();
}
显然,使用静态只是出于说明目的。
它现在可以工作的事实是一个意外。 如果要强制计算机在每次通过循环时都重新检查它,则需要声明变量volatile
。 否则,它可能只读取一次该值,而不再查看它。
此外,像这样的繁忙等待循环效率极低。 相反,如果您想在获胜时退出,请首先使用设置该标志的代码直接调用关闭代码。
您有一个不断等待的繁忙等待循环。
为了减轻压力,您可以这样做:
Thread,sleep(100L);
相反,如果System.out.prinntln。
这不是一个干净的解决方案。
顺便说一句:相反,如果
hasWon = hasWon && (board[i][z].getStatus() == winCond);
这有点快
if (board[i][z].getStatus() != winCond) {
return false;
}
最好还是保留一下winConds。
因此,最好的解决方案是删除循环并更改网格,增加/减少计数器,并在那里赢得出口,
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.