2011-01-05 24 views
1

下面是我目前正在建設一個Web服務器的一個片段:奇特行爲多線程/ volatile變量/條件句/環路(JAVA)

// ...

threadPool = Executors.newCachedThreadPool(); 
while (true) 
    if(this.isOn) { 
       try { // listen for incoming connection 
       this.clientSocket = serverSocket.accept(); 
     } catch (IOException e) { 
        System.err.println("LOG: >> Accept failed! "); 
        System.exit(1); 
        } 
     // as soon as a connection is established send the socket 
     // with a handler/processor to the thread pool for execution 

        threadPool.execute(new ClientRequestProcessor(clientSocket)); 
     } 

// ...

請注意,isOn變量是一個VOLATILE布爾值。

如果我把這個if變成了一段時間......這段代碼有效......但事實並非如此。請問爲什麼?從邏輯的角度來看,兩者都應該工作,即使我在一個if中測試該標誌......我是否錯過了某些東西?!

[稍後編輯:]不工作我的意思是...一個瀏覽器(例如firefox)無法連接,實際上它不斷嘗試但最終超時。再一次,如果我改變,如果(isOn)變成一段時間(isOn),它就像一個魅力。

任何建議/想法都非常歡迎!

P.S.我需要這個組合「while(true)if/while(test flag){...}」,因爲服務器可以從GUI啓動/停止......所以最高級別while(true)是需要的,所以我可以重新檢查我是否在(並因此監聽連接)或者我是否關閉(並且不關心傳入連接)。針對GUI的事件處理程序可以隨時修改標誌。

回答

2

一個更好的解決方案是當你希望它停止時關閉服務器套接字,並在你想要啓動一個新線程時啓動一個新套接字。這樣你就可以拒絕新的連接,並且當它沒有做任何事情時不會消耗CPU。

當isOn == true並且將其設置爲false時,它將僅在下一次新連接後才接受連接。 (可能在任何時候以後)另外,任何客戶端新連接都會等待接受被調用(或最終超時)。默認情況下,您可以有多達50個連接等待接受。

當isOn == false時,您的線程將忙於等待,消耗一個CPU。我建議你放一些延遲,如Thread.sleep(250)。這會大幅削減CPU,但不會延遲太多的啓動。

BTW:

  • 如果你得到一個例外,你應該記錄/打印出來。否則,當它失敗時,你將不知道爲什麼。
  • 如果接受失敗,可能是進程沒有文件,所以你不希望它死掉,殺死所有現有的連接。
+0

我完全同意你所說的話。另外,將標誌更改爲false仍然可以保證在服務器實際「停止服務」之前另一個「正在監聽連接」。但是,這仍然不能解釋我使用當前版本的代碼時出現的不規則行爲!我可能會採用你的解決方案,但我仍然很好奇爲什麼一個版本可以工作,而另一個不是......當邏輯上都應該。問題並不是真的如果有更好的解決方案(你已經證明存在!),而是爲什麼這個java代碼行爲如此笨拙...... – Tibbers 2011-01-05 10:00:57

+0

@Tibi,while(true)if(flag)while while(true)而(國旗)在你的情況下應該是相同的。我懷疑你的測試不穩定可重現。 – 2011-01-05 13:40:46

+0

再說一次,你也可以在這一個上。因爲如果我使用調試器運行if-variant並逐行執行代碼,那麼它完美工作......但是,如果我只是運行並保持獨立,if-variant不起作用!所以,實際上我可能無法重現機器的實際狀態,因此任何試圖理解這種尷尬行爲的嘗試都是徒勞的。無論哪種方式,感謝您的及時迴應......您的(初始)重構/重新設計主張已經實施並且像魅力一樣起作用! – Tibbers 2011-01-07 09:48:14

0

如果你有while(true)然後if(this.isOn)while循環無法停止。當isOn標誌變爲false時會發生什麼。 while循環從不停止,因爲它基本上是無限的。插入一個else語句使其中斷,它應該按預期工作。

如果您取出if語句並且只是將其設置爲while(this.isOn),那麼當isOn標誌變爲false時,循環結束。沒有無限循環。

這些都是我的想法乍一看...

+0

嗨!你讀過我的P.S.嗎?當我說把if變成while時,我的意思是>>>> while(true)while(this.isOn){...} <<,它的工作原理就像這樣...就像在連接成功建立一樣! – Tibbers 2011-01-05 09:29:58

+0

他不想退出循環,只是繞着(true)等待如果成爲真實。意想不到的行爲是,如果(isOn)永遠不會變爲真,那麼就不會嘗試接受(),但是如果他有,while(isOn)它會。 – djna 2011-01-05 09:41:17

+0

你是部分正確的djna。 Eclipse中的調試器表示該標誌確實成爲真實。並在某個時候將新的處理程序發送到線程池。但由於某種原因,它不起作用。但是,如果我改變它,如果它在奇蹟般地工作(沒有任何其他修改代碼中的任何修改)! – Tibbers 2011-01-05 09:49:40

0

我的假設將根據您的緊密循環出現。是否有可能在服務器上運行了多個程序實例?如果將isOn設置爲false,if(isOn)版本將不會關閉,而只會循環永久刻錄CPU。