2014-02-19 93 views
1

我正在爲Java遊戲編寫一個Java程序。一個線程爲Manager和Worker線程管理時間併爲它們發送檢測信號。 Manager收集並解釋來自服務器的消息,並且Worker線程從Manager接收命令(具有類中的詳細信息)並對此信息起作用。Java中的多線程死鎖

現在,我遇到了多線程死鎖問題,我不確定是否有替代方案。

以下是我的管理器類中的一些方法:當用戶單擊按鈕時,我從GUI線程中調用getMessageFromUsername。以下方法從另一個線程中調用。

private ArrayList<Message> MessageList = new ArrayList<>(); 

public synchronized Message getMessageFromUsername(String username) {   
     for(Message msg : MessageList) { 
      if(msg.username.equalsIgnoreCase(username)) { 
       Message m = new Message(msg.num, msg.username, msg.id);     
       return m; 
      } 
     } 

     return null; 
    } 

我的管理器線程從套接字讀取信息,並在連續循環中向MessageList添加信息。 (另外一個,即)

private synchronized void parseMessage() {} 
private void main() { while(1) { parseMessage(/*Adds message to MessageList*/); Sleep(); } } 

現在,我的問題是一個相當noobie發出─因爲如果我要寫信給我MessageList中必須使用同步訪問。但是,由於這發生在一個循環中,並且消息不斷通過套接字進入,它會導致死鎖,因爲它會一直鎖定我的對象,並且這發生在循環中。

我該怎麼做才能解決死鎖問題?

+0

最簡單的方法是在循環中添加一些暫停。你可以使用'Thread.sleep()' –

+0

我在我的循環中使用了100毫秒的暫停,但由於某種原因它仍然發生死鎖。什麼是暫停的好時機? – Jason

+3

錯錯了錯! @ bali182請說你在拖他!睡眠怎樣才能成爲僵局的妥善解決方案?另一方面,你究竟在哪裏看到了僵局?你在這裏是一個飢餓的線程的例子。 '同步的'原語不適合你,你應該選擇一些優先機制。 –

回答

1

正如我在評論中所說,你沒有死鎖,但你餓死你的線程。

你有兩個選擇:

  • 要麼你去一些主題與優先排序

  • ,或者你去併發啓用集合。 java.util.concurrent有很多這樣的集合的例子。但要小心 - 修改一個被濫用的集合永遠不是一個好主意。也許你只需要一種fifo隊列?一個線程添加一條消息,另一個線程彈出並評估?

例如有ConcurrentLinkedQueue,提供Add方法和isEmpty()(由您parseMessage使用)(在一個while循環的其他線程的使用)。

雖然我不是Java專家,但我會指出您的答案:How to use ConcurrentLinkedQueue?它提供了一些實用建議。

+0

謝謝。我正在尋找線程餓死現在。看起來我錯了,它是一個僵局。 – Jason

+0

請看看我的編輯和鏈接 –

+0

將優先級分配給線程時的一般經驗法則:給出釋放資源優先級的線程而非佔用線程的線程。將消息添加到隊列的線程正在消耗資源(內存)。從隊列中移除消息並執行某些操作的線程(可能)在釋放內存時釋放內存。 –

2

我認爲主要的問題是,你似乎在等待消息到達時保持鎖定狀態。

當您開始閱讀郵件時,您可以通過parseMessage()進行鎖定,郵件可能一段時間不會到達,另一個線程在消息到達之前無法做任何事情。然後它可能會錯過它的機會......(等待/通知可能會解決問題的後半部分,但我認爲這不是必需的)。

我會重新調整如下:

// just parse and return the message, don't add it to the list 
private Message parseMessage() {}  

private void main() { 
    while(1) { 
     Message msg = parseMessage(); 
     synchronized(messageList) { 
     messageList.add(msg); 
     } 
    } 
} 
+0

在我看來,雖然儘可能少地同步並且在任何IO上同步是一個壞主意,但值得一提的是,這不能解決飢餓。就像睡眠一樣,它只是移動壓力,並且(很大程度上)增加了線程交織的機會,但是從理論的角度來看並沒有提供任何保證。在這種情況下它可能會有很大的幫助,但是;-) –

+0

那麼你在改變的程序中看到了飢餓的可能性呢? –

1

如果我理解你的使用情況正確的話,我相信,我會考慮使用的BlockingQueue實現你的郵件列表。如前所述,還提供了併發實現,因此您不需要外部同步。您應該能夠從隊列中簡單地輸入poll()take()

0

我認爲你應該使用ArrayBlockingQueue並避免使用循環,而是用諸如poll/take/put/offer之類的阻塞方法替換循環。

基於數組的集合表現更好,所以您應該先考慮這些基於鏈接節點的集合。所以ArrayBlockingQueue比ConcurrentLinkedQueue更好。