2016-05-16 69 views
0

我有這個Transmitter類,其中包含一個BufferedReader和一個PrintWriter。這個想法在主類中使用Transmitter.receive()和Transmitter.transmit()到主套接字。問題是:加入後Java線程卡住

public void receive() throws Exception { 
     // Reads from the socket 
     Thread listener = new Thread(new Runnable() { 
     public void run() { 
      String res; 

      try { 
      while((res = input.readLine()) != null) { 
       System.out.println("message received: " + res); 

       outputMessage = (res); 

      if (res.equals("\n")) { 
       break; 
      } 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     }; 
    }); 

    listener.start(); 
    listener.join(); 
    } 

線程更改'outputMessage'的值,我可以使用輔助方法得到的值。問題是,如果沒有加入,我的客戶端獲取outputMessage,但我想用它幾次在我的主類,像這樣:

trans1.receive(); 
while(trans1.getOutput() == null); 
System.out.println("message: " + trans1.getOutput()); 

但隨着加入這個System.out的永遠不會執行,因爲trans1.receive()被卡住。 .. 有什麼想法嗎?

編輯1:這裏是發射器類https://titanpad.com/puYBvlVery

+0

不幸的是,問題不可重現。你介意請發佈一個可運行的代碼。 –

+0

while((res = input.readLine())!= null)的唯一循環,但它不是null,因爲我的erlang服務器通過套接字發送東西。證明是,如果我刪除'join()'它的工作原理:/ –

+0

我認爲你的循環在線程永遠不會結束;當輸入用完時,它會被阻塞。所以線程永遠不會結束,連接也不會發生。發送完數據後,另一端是否關閉了套接字? – antlersoft

回答

3

您可以發送\n;這並不意味着你會在你的Java代碼中看到它。

正如它在Javadoc for BufferedReader.readLine()(重點煤礦)表示:

(返回)包含行的內容的字符串,不包括任何行終止符

所以"\n"永遠不會被退回。

+0

是的,它不返回「\ n」,但直到它讀取「\ n」,這就是即時消息,服務器發送「消息\ n」,所以讀者讀取並從循環中斷。但即使如此,它似乎永遠留在循環中 –

+0

請閱讀報價:該方法不會返回您發送的行終止符。如果你發送*只是*'「\ n」',它會返回'「」'。 –

+0

是的,我知道Andy,但我不想要「\ n」,通過erlang方法將「\ n」發送到套接字。 Erlang發送「string \ n」,並且receive()讀取行直到「\ n」並從循環中斷開。當循環中斷時,我想要這個消息的值。 –

1

這樣做:

{ 
    Thread listener = new Thread(new Runnable() { 
    public void run() { 
     doSomeWork(); 
    }; 
    }); 

    listener.start(); 
    listener.join(); 
} 

將創建一個新的線程,然後等待它完成它的工作和完成。因此,它或多或少一樣乾脆直接做:

doSomeWork(); 

新的線程不會服務於任何真正的目的在這裏。

此外,額外的線程引入了同步問題,因爲在你的代碼中你不能確保你的變量是同步的。

第三,你的線程在循環中保持從輸入讀取行,直到沒有其他東西要讀取,除非另一端關閉流,它將阻塞readLine()調用。用getOutput()看到的內容將是一條隨機線,恰好在你看的時候出現,下一次你看它可能是同一條線,或者一些完全不同的線;一些行將被直接閱讀和遺忘,而你從來沒有從主線看到它。

當您實際需要從輸入中獲取新行消息時,您可以直接在主線程中調用input.readLine(),而不需要額外的讀取器線程。你可以按照yshavit的建議將讀取的消息存儲到隊列中,如果需要的話,例如出於性能方面的原因,可能會更好地在消息可用時立即閱讀消息,並將消息準備好在內存中。但是如果你只需要逐一讀取消息,那麼只有當你真正需要時才能調用input.readLine()。

+0

哇,這是一個非常有趣的觀察。所以輔助類中的線程是愚蠢的: trans1.receive(); while(trans1.getOutput()== null); System.out.println(「message:」+ trans1.getOutput()); 不需要?問題是,我使用掃描儀從用戶那裏獲得輸入,根據這個答案,我發送一個字符串到套接字,然後服務器處理併發送響應。我該怎麼辦?只需在主客戶端類上使用readLine()?非常感謝你的分析......我真的很感謝 –

+0

你似乎知道很多。老實說,我的未來取決於這項工作的質量,你會考慮做一個5分鐘的代碼審查?而且我明白,如果你不會免費提供,請提前致謝。 –

+1

@JoãoVilaça:如果你有興趣的話,有一個_Code Review_網站(見本頁底部的鏈接)。如果您確實使用它,請務必閱讀他們的主題規則,以便充分利用它。 – halfer