2014-02-19 3 views
1

나는 게임을 위해 자바로 봇을 쓰고있다. 하나의 스레드는 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(); } } 

지금, 내 문제는 내가 MessageList의 쓰기하려면 때문에 나는 그것을 액세스 할 수 동기화 사용해야하는 문제 - 꽤 noobie이다. 그러나이 루프에서 발생하고 메시지를 끊임없이 내 개체를 잠그기 때문에 교착 상태가 발생하고 소켓을 통해 들어오는 및 루프에서 발생합니다.

교착 상태 문제를 해결하려면 어떻게해야합니까?

+0

가장 쉬운 방법은 루프에 일부 일시 중지를 추가하는 것입니다. 당신은'Thread.sleep()'을 사용할 수 있습니다. –

+0

루프에서 100 밀리 초의 일시 중지를 사용하고 있지만, 어떤 이유로 인해 여전히 교착 상태입니다. 멈출 수있는 좋은 시간은 무었입니까? – Jason

+3

잘못 잘못 잘못되었습니다! @ bali182 당신이 그를 조롱하고 있다고 말하십시오! 어떻게 교착 상태에 대한 적절한 해결책이 될 수 있겠습니까? 반면에 정확히 어디에서 교착 상태가 발생합니까? 여기에있는 것은 굶주린 실의 예입니다. 'synchronized' 프리미티브는 당신을위한 해결책이 아니므로 우선 순위가 매겨진 메커니즘을 찾아야합니다. –

답변

1

내가 코멘트에서 말했듯이, 당신은 교착 상태가 없지만, 당신은 당신의 스레드를 굶어 죽입니다.

당신은 두 가지 옵션이 있습니다

  • 중 하나는 우선 순위

  • 주문으로 일부 스레드 이동 또는 동시성 활성화 컬렉션에 대한 이동합니다. java.util.concurrent에는 그러한 컬렉션의 많은 예가 있습니다. 그러나 foreground 컬렉션을 수정하는 것은 결코 좋은 생각이 아닙니다. FIFO 큐가 필요 하겠지? 한 스레드는 메시지를 추가하고 다른 스레드는 메시지를 추가하고 평가합니다.

Add 방법을 제공하는 것을 ConcurrentLinkedQueue가 있고 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보다 좋습니다.