[英]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.