2011-03-13 54 views
2

我有一段代碼,看起來像這樣:在我的網格類)奇怪的Java問題,而循環終止

Algorithm a = null; 
while(a == null) 
{ 
    a = grid.getAlgorithm(); 
} 

信息getAlgorithm(這取決於用戶從某些選項選擇算法的某些亞型返回。

我的問題是,即使在選擇算法後,循環也不會終止。但是,如果我只是放置一個System.out.println(「Got here」),那並不是棘手的問題。在我調用getAlgorithm()之後,程序運行得非常好,循環終止了。

我的問題是:爲什麼添加那個magic print語句突然讓循環終止?

此外,當我開始使用我的新筆記本電腦時,這個問題首次出現,我懷疑這是相關的,但我認爲這值得一提。

編輯:有問題的程序不是多線程的。 getAlgorithm()的代碼是:

public Algorithm getAlgorithm() 
{ 
    return algorithm; 
} 

其中算法最初爲空,但會在某些用戶輸入時更改值。

+5

哦,親愛的請告訴我,您在等待用戶輸入時不會像這樣循環... – 2011-03-13 03:49:22

+0

發生這種情況的唯一方法就是如果返回null。如果它不爲null,則循環將退出。檢查'getAlgorithm()'的來源或在循環中打印出它的內容以確認它不爲空。 – berry120 2011-03-13 03:52:17

+0

@Travis - 看起來更像是一個迭代器,對第一個非空算法進行線性搜索。但是誰知道? – 2011-03-13 03:52:42

回答

1

您正在進行活動輪詢。這是一個不好的做法。你應該至少讓輪詢線程睡眠(使用Thread.sleep)。由於println做了一些io,它可能就是這麼做的。如果你的應用不是多線程的,那麼它根本不可能工作。

+0

你怎麼知道這是主動投票?誰知道getAlgorithm()裏面發生了什麼? OP沒有告訴我們。也許每次調用都會改變'grid',所以每個調用可能會返回一個不同於前一個值的值。 – 2011-03-13 03:55:40

+0

op的說明表示等待用戶輸入。這個問題似乎是一個同步問題。特拉維斯似乎同意。像這樣在一個循環中變換一個網格,即一個UI對象將是一個糟糕而混亂的做法。聽起來像是一個公平的賭注給我。 – 2011-03-13 03:59:07

+0

有趣的是,我的舊電腦上的代碼運行正常,但在我的新電腦上運行它會產生這種特殊的錯誤。所以我知道理論上的代碼應該工作。 – Deomachus 2011-03-13 04:01:06

1

如果此循環等待GUI中的用戶輸入,那麼ouch。壞,壞主意,甚至Thread.sleep()補充說我永遠不會推薦它。相反,你很可能想要在有問題的組件上註冊一個事件監聽器,並且只有當內容改變時纔會觸發驗證代碼。

由於您已經達到了某種形式的死鎖,尤其是在您的應用程序是多線程的情況下,您的程序鎖定的可能性很大。我不會試圖解決這個問題並且繞開它,我會認真考慮重新設計應用程序的這部分工作方式。

+0

如果他的循環寫成:'while(!line.equals(「stop」)){line = getNextLine(); '',你會稱這是一個「壞主意」嗎?我在這裏沒有看到任何區別。 – 2011-03-13 04:10:51

+0

我編輯了我的帖子,使其更清晰,但我的意思是他是否在某種形式的GUI上進行輪詢,這是一個糟糕的主意。與getNextLine()不同的是,你實際上每次都會獲得新的東西。 – berry120 2011-03-13 04:18:40

+0

OP寫道:「我的網格類中的getAlgorithm()返回算法的一些子類型,取決於用戶從某些選項中選擇的內容。」聽起來像一個榮耀的'getNextLine()'給我。 **但**基於OP的編輯(在我的評論之後完成),我同意這裏存在線程問題。 – 2011-03-13 17:23:43

0

您應該檢查getAlgorithm()方法中是否存在錯誤。

2

我認爲這個問題必須處理如何執行grid.getAlgorithm。如果執行該方法的代價很小,那麼只要方法繼續返回null,while循環就會非常快速地循環。這通常被稱爲busy wait

現在聽起來好像您的新筆記本電腦遇到starvation問題,該問題並未在您的舊電腦上顯示。很難說爲什麼,但如果你看看我上面提到的鏈接,維基百科的文章確實表明忙碌的等待確實有不可預知的行爲。也許你的舊電腦比你的新電腦更好地處理用戶IO。無論如何,在您的新筆記本電腦上,該環路正在將資源從處理您的用戶IO的任何東西中分離出來,因此它正在扼制負責打破環路的流程。

0

有兩種情況:

  1. 你的代碼是真的不意味着是多線程的。在這種情況下,您需要在循環中插入某種用戶輸入。否則,你可能會留下它作爲算法a = grid.getAlgorithm();並防止無限循環。
  2. 你的代碼是多線程的,在這種情況下你有某種'可見性'問題。請轉至Atomicity, Visibility and Ordering或閱讀Java Concurrency in Practice以瞭解有關可見性的更多信息。從本質上講,這意味着如果沒有線程之間的某種同步,您正在循環的線程可能永遠不會發現由於JVM可能執行的優化而發生的值已更改。

您沒有提及任何有關此代碼運行的上下文。如果它是一個基於控制檯的應用程序,並且你從一個'main'函數開始,你會知道是否有多線程。因爲你說沒有多線程,我認爲情況並非如此。另一種選擇是,這是一個擺動應用程序,在這種情況下,您應該閱讀Multithreaded Swing Applications。這可能是一個Web應用程序,在這種情況下,可能會出現類似的情況。

在任何情況下,您都可以調試應用程序以查看哪個線程正在寫入「算法」變量,然後查看哪個線程正在讀取它。

我希望這是有幫助的。無論如何,如果您在問題中提供更多的上下文,您可能會找到更多幫助。特別是對於一個像'怪異的Java問題,循環終止'這樣有趣的標題的問題。