有人知道为什么这个 while Look 仅在存在 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()));
}
这是一款益智游戏,用户单击图 block ,相邻图 block 也会发生变化。然而,当拼图完成时,如果没有 println(),它不会显示完成,如果有 println(),它会退出循环并退出程序。
再次强调,如果 while 循环内有 println() ,则一切正常。当我注释掉它时,它不起作用。
最佳答案
您所拥有的是一个紧密的 CPU 密集型循环,它重复调用 hasWon()
。看起来还有其他线程负责更新棋盘状态,从而导致“获胜”位置。
看起来问题是紧密的 CPU 循环导致其他线程挨饿,插入 println
足以让线程调度程序重新调度。
另一种可能的解释是,您有一个共享数据结构,一个线程正在读取,另一个线程正在更新......没有任何同步。从理论上讲,您没有同步的事实可能意味着读取线程永远不会看到更新线程所做的更改,因为编译器没有看到需要插入将导致相关缓存刷新等的“屏障”指令.
正如 @chrylis 所指出的,像这样的忙碌循环效率非常低。您需要做的是替换繁忙循环:
一个巧妙的解决方案是将
<Thread.sleep()
调用放入循环中(而不是println
调用)。更好的解决方案是使用
Object.wait()
和Object.notify()
。主线程在每次检查后对互斥对象调用wait()
,而正在执行更新的线程每次执行操作时都会对同一个互斥对象调用notify()
可能会导致“赢得”位置的更新。
第二个解决方案还处理同步问题。 wait()
和 notify()
方法只能在持有互斥体时执行;即在同步
block 或方法中。
下面是一些代码片段,展示了如何实现等待/通知。
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();
}
显然,静态的使用只是为了说明目的。
关于Java:While循环不退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23939330/