2017-02-27 69 views
1

我在Java中遇到了這個問題。 我有一個名爲MyServer的服務器類,我想實現一個線程池,每個線程在請求​​發出時運行MyServer的一個方法。我創建了另一個實現了名爲MultiThreadedSocketServer的服務器池的類。類是這樣的:Java中的線程池中的協調問題

public class MultiThreadedSocketServer { 

public void startServer(MyServer s, int localport, int threadPoolSize) { 
    final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(threadPoolSize); 

    Runnable serverTask = new Runnable() { 
     @Override 
     public void run() { 
      try { 
       ServerSocket serverSocket = new ServerSocket(localport); 
       System.out.println("Waiting for clients to connect..."); 

       while (true) { 
        Socket clientSocket = serverSocket.accept(); 
        clientProcessingPool.submit(new ClientTask(clientSocket, s)); 
       } 
      } catch (IOException e) { 
       System.err.println("Unable to process client request"); 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Thread serverThread = new Thread(serverTask); 
    serverThread.start(); 
} 
} 

名爲MultiThreadedSocketServer類具有通過它在一個線程創建客戶端Task類參數名爲Server秒。客戶端的任務類是這樣的:

class ClientTask implements Runnable { 
    private final Socket clientSocket; 
    private MyServer s; 

    public ClientTask(Socket clientSocket, MyServer s) { 
     this.s = s; 
     this.clientSocket = clientSocket; 
    } 

    @Override 
    public void run() { 
     System.out.println("Got a client !"); 

     String inputLine = null; 
     try { 

     BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
     // Do whatever required to process the client's request 
     inputLine = in.readLine();   

     if (inputLine.equals("Bye")) { 
      System.out.println("Bye"); 
      System.exit(0); 
     } 

     s.handleRequest(inputLine); 

      clientSocket.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

正如你可以看到,當請求類的MyServer的的handleRequest方法被調用。我想讓這個方法運行synchronized,意味着一次只能有一個線程能夠運行這個方法。在方法實現之前添加synchronized並沒有達到任何效果。

任何人都可以給我正確的方法來做到這一點? 預先感謝您的時間。

PS:我加入了全碼

的MyServer類 http://pastebin.com/6i2bn5jj

多線程服務器類 http://pastebin.com/hzfLJbCS

由於這是顯而易見的主要創建三個請求用的handleRequest帶參數的任務,TASK2和再見。

正確的輸出將

Waiting for clients to connect... 
Got a client ! 
This is an input Task 
Request for Task 
Got a client ! 
This is an input task2 
Request for task2 
Got a client ! 
This is an input 
Bye 

而是順序混合。有時關閉服務器的Bye可以先執行。我想確保訂單是主要創建請求的訂單。

+0

使MyServer.HandleReq()同步將阻止多個線程在同一個MyServer實例**上同時調用該方法**。你有多少個MyServer實例?附註:請尊重命名約定。 –

+0

只有一個MyServer實例會一直運行。 對不起,我不知道命名約定,如果你想澄清我將編輯我的帖子 –

+1

方法開始一個小寫字母。 HandleReq應該是handleReq,或者甚至更好,handleRequest。變量一樣。 ThreadPoolSize應該是threadPoolSize。如果您有一個MyServer實例,那麼同步該方法即可。你如何測試它沒有正確同步? –

回答

2

但相反,訂單是混合的。有時關閉服務器的Bye可以先執行。我想確保訂單是主要創建請求的訂單。

你說你希望服務器按順序處理請求。這很難確保,因爲您打開了3個套接字並將它們寫入服務器,但沒有等待任何響應。這是依賴於實現的,但我不確定是否有任何保證,當客戶端從套接字InputStream寫回來時,服務器已收到字節。這意味着從客戶端,不能保證IO按您想要的順序完成。

要查看這是否是問題,我將刪除System.exit(0)以查看其他行是否在"Bye"字符串之後創建它。或者你可以在exit(0)之前加上Thread.sleep(5000);

一種簡單的修復方法是確保您的PrintStream已啓用自動刷新功能。至少會在套接字上調用flush,但即使如此,客戶端和服務器之間也存在競爭狀態。如果自動刷新不起作用,那麼我會讓你的客戶端等待來自服務器的響應。那麼第一個客戶端會在寫入第一個命令並等待確認之後再進入第二個命令。

就原來的問題而言,由於競爭條件的原因,鎖定服務器將無濟於事。 "Bye"可能會首先將服務器鎖定並將其鎖定。

這些圍繞如何在多線程程序中同步線程的問題對我來說確實沒有意義。線程的整個是它們並行運行並且不必按任何特定順序運行。您越強迫程序以特定順序吐出輸出內容,您越是爭論沒有任何線程的寫作。

希望這會有所幫助。

0

如果問題是bye消息在可以處理其他請求之前殺死服務器,則一種解決方案可能不會在bye上調用System.exit(0);

bye消息可能會設置一個標誌塊來處理進一步的請求,並且還會通知某些其他機制在線程池處於空閒狀態並且沒有任何請求需要處理時調用System.exit(0);