2012-06-08 85 views
1

我有兩個條件,一個在另一個裏面,用布爾值來控制它們。基本上,一個是終止一個共享,另一個是傾聽連接。用戶可以選擇禁用共享,在這種情況下,服務器會停止監聽,但不會終止。如果用戶選擇終止,則兩個布爾值都設置爲false,並結束循環。爲什麼不重新評估條件?

這是我的代碼:

 public void run() { 
      while (!terminate) { 
       while (listening) { 
        try { 
         // accept connection -> create a new thread for each client 
         ClientServerShareInstance clientServerShareInstance = new ClientServerShareInstance(serverSocket.accept(), ui); 
         Thread clientServerThread = new Thread(clientServerShareInstance); 
         clientSockets.add(clientServerShareInstance); 
         connectedClients++; 
         clientServerThread.start(); 
        } catch (IOException ex) { 
        } 
       } 
      } 
     } 

     public void closeAllClientConnections() { 
      for (Iterator it = clientSockets.iterator(); it.hasNext();) { 
       ClientServerShareInstance clientServerShareInstance = (ClientServerShareInstance) it.next(); 
       clientServerShareInstance.closeAllConnections(); 
       it.remove(); 
      } 
      try { 
       this.serverSocket.close(); 
      } catch (IOException ex) {} 
      this.setActive(false); 
      this.connectedClients = 0; 
     } 


     public void openConnection() { 
      try { 
       serverSocket = new ServerSocket(portNumber, 0, Inet4Address.getLocalHost()); 
       setActive(true); 
      } catch (IOException ex) {} 
     } 
    } 

closeAllClientConnections()方法禁用份額(不終止它),而且份額openConnection()重新啓用。

問題是,如果我禁用共享,它應該循環terminate而無限期地cicle,測試值listening。當我將listening設置爲true時,它應該在循環中重新輸入第二個字符,然後再次開始監聽,因爲我打開了服務器套接字(儘管它與此無關,我只是說它必須再次被初始化,因爲我關閉了它當我禁用共享)。但是,禁用後,即使調用openConnection(),也不會租用listening循環。

有人知道這裏有什麼問題嗎?

+0

'SETACTIVE( ...)'設置'聽'的價值? – Gray

+0

不,他們只是在我的班級裏宣佈爲常規私人布爾人。我沒有使用volatile,因爲我認爲對象是在多個線程之間共享的,而且我不需要鎖定,因爲它不是一個複雜的操作,多個線程同時「爭奪」訪問權限。 – swiftcode

+0

@Gray是的,它的確如此。它只是這個變量的二傳手。 – swiftcode

回答

3

沒有足夠的代碼顯示任何錯誤。但是這裏有一些評論可能會有所幫助。

  • 無論是shutdownlistening布爾必須volatile。線程之間共享的任何字段需要以某種方式同步,否則對其值的更改將不會被其他線程看到。

  • serverSocket也將需要volatile,因爲它似乎是由openConnection()調用者創建,但在while循環消費。您可以考慮將openConnection()中的true設置爲true,並且完全由接受線程管理serverSocket

  • clientSockets看起來是一個集合。這將需要是一個同步連接,因爲它看起來像是由多個線程訪問。再次,更好的模式將是closeAllClientConnections()調用只需設置一個布爾值,並且線程本身將執行關閉。這可以消除使用集合等方面的任何競爭條件。

  • 看起來如果你是! terminating你的接受線程將旋轉。至少你應該把一些Thread.sleep(100)或其他東西放慢速度。等待/通知甚至會更好。

重要的是要認識到,它是重要的是不要只是會發生什麼「同時」在某個線程程序。這也與內存緩存有關。接受線程可能在一分鐘前向clientSocketsArrayList1添加了一些內容,如果列表未以某種方式同步,另一個線程可能不會看到這些更改。更糟糕的是,ArrayList的某些部分可能已在內存中更新,但不會導致異常的其他部分更新。爲了得到一個同步採集,您應該創建ArrayList這樣的:

List<...> clientSockets = Collections.synchronizedList(new ArrayList<...>()); 

聽起來像是你應該閱讀一些關於爲什麼同步是必須的文件:

http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

+0

serverSocket在那裏創建,但它主要是一個重新實例化,因爲它首先在run()方法中初始化(在首次創建共享時)。 – swiftcode

+0

Reinstantiation仍需要同步@Lovato。如果任何字段的更改被多個線程更改,則需要對其進行同步。此外,構造函數優化周圍存在很多複雜性,可能會導致構建套接字但未完全初始化。如果可以的話,你應該避免在一個線程中構建它並在另一個線程中使用它。 – Gray

+0

clientSockets是客戶端套接字的ArrayList。當我禁用共享時,我必須關閉連接到該共享的所有客戶端,因此我將它們存儲在集合中,調用closeAllConnections()並關閉每個客戶端的所有連接,然後將它們從列表中刪除。 – swiftcode