2015-02-10 109 views
0

我遇到了一個問題,我有一個類在連接到服務器時得到實例化。同步數據輸出流

我在課堂上遇到問題的方法看起來像這樣:

public void sendData(byte[] dataToSend) throws IOException { 
    sendLock.lock(); 

    int dataLength = dataToSend.length; 
    dout.writeInt(dataLength); 
    dout.write(dataToSend, 0, dataLength); 
    dout.flush(); 

    sendLock.unlock(); 
} 

其中 「sendLock」 是的ReentrantLock,DOUT是DOUT =新的DataOutputStream類(socket.getOutputStream()); 這將適用於有限數量的線程,但如果我有大量的線程同時調用此方法,則會發生死鎖,並且程序停止。死鎖會在這裏發生嗎?這對我來說沒有任何意義,因爲我已經刪除了所有其他的鎖以排除它們,而我只能選擇這個鎖。無論如何,沖洗可能會導致事情掛起或什麼?它似乎在某種程度上它永遠不會釋放鎖,我不知道爲什麼。

如果我刪除鎖,我得到套接字錯誤,因爲一個線程可能會在另一個線程有可能寫入數據之前更改dataLength等等,但死鎖不再發生。

作爲參考,這裏是接收端的run方法是這樣的:

public void run() { 

    while (socket != null) { 
     try { 
      int dataLength = din.readInt(); 
      byte[] data = new byte[dataLength]; 
      din.readFully(data, 0, dataLength); 
      Event e = ef.getEvent(data); 
      node.onEvent(e);  
     } catch (SocketException se) { 
      System.out.println(se.getMessage()); 
      break; 
     } catch (IOException ioe) { 
      System.out.println(ioe.getMessage()) ; 
      break; 
     } 
    } 
} 
+0

爲什麼你會有大量的線程發送數據到同一個套接字?注意你的接收代碼應該單獨捕獲'EOFException',而不記錄它:這是正常的。您還應該在'DataOutputStream'和套接字輸出流之間添加'BufferedOutputStream'。 [否則'flush()'是多餘的。] – EJP 2015-02-10 23:48:26

+0

客戶端互相發送數據。可能在任何時候,例如,客戶端A和客戶端B都向客戶端C發送數據。 – shparkison 2015-02-11 00:42:37

+0

實際上,現在我想到了。你是對的,輸出流被綁定到套接字上,不知道爲什麼我在想這個!這實際上有幫助,並且可能是我弄亂了的地方。實際上,我爲每個客戶端運行兩個線程,一個用於發送,另一個用於接收。接收線程可能需要轉發消息,所以此時可能客戶端A的發送和接收都嘗試使用相同的輸出流發送...... – shparkison 2015-02-11 00:54:15

回答

2

這有可能是你的電話到輸出流的一個拋出一個異常,sendLock.unlock()永遠不會被調用。所有其他線程將永遠等待。

檢查您的日誌,看看其中一個線程是否引發異常。在你的代碼中,我會使用try-catch-finally塊而不是拋出IOException。這保證即使發生了不好的事情,鎖也會被釋放,以便其他線程可以繼續工作。

public void sendData(byte[] dataToSend) throws IOException { 
    try { 
     sendLock.lock(); 

     int dataLength = dataToSend.length; 
     dout.writeInt(dataLength); 
     dout.write(dataToSend, 0, dataLength); 
     dout.flush(); 
    } 
    finally { 
     sendLock.unlock(); 
    } 
} 
+2

附註:不需要「catch」塊。拋出異常似乎是更合適的事情,因爲調用者會想知道錯誤(即重試)。 – duckstep 2015-02-10 23:55:09

+0

@duckstep同意。我已經刪除了「catch」塊。它可能在這裏被捕獲用於記錄目的,但它不是必需的。 – 2015-02-11 00:02:28

+0

謝謝,這很有幫助!將看看它是否有助於解決我的問題。 – shparkison 2015-02-11 00:52:12