2017-12-07 2 views
0

서버가 클라이언트에서 메시지를 수신 할 때마다 메시지가 대기열에 저장됩니다. 여러 스레드가 대기열에 데이터를 입력 할 수 있지만 한 번에 하나의 스레드 만 읽거나 처리해야합니다. 대기열에 메시지가있는 한 처리 스레드가 살아 있어야합니다. 이 작업을 어떻게 수행합니까?메시지 대기열이 비어 있지 않으면 처리 스레드를 항상 실행하십시오.

처리 로직을 동기화 된 메서드에 넣고 모든 요청에 ​​대해이 메서드를 호출하는 새 스레드를 시작하면 메모리에있는 모든 스레드가있는 리소스가 낭비되지 않고 차례를 기다리고 있지 않습니까? 나는 각 요청을 시작하려고로, 하나의 처리 스레드를 사용하는 경우 다른 한편으로

, 이미 실행되어 있지 않은 경우 :

public void onMessage(String message) { 
    addToQueue(message); 
    synchronized (lock) { 
     if (!processingThread.isAlive()) 
      processingThread.start(); 
    } 
} 

// processing thread 
public void process() { 
    while (true) { 
     String message = queue.poll(); 
     synchronized (lock) { 
      if (message == null) 
       return; 
     } 
     // process message 
    } 
} 

어떻게 내가이 시나리오에 실행되지 않도록 할 수 있습니다 :

  1. 처리 스레드는 다음 요소에 대한 대기열을 폴링합니다. 공유 잠금을 가져 와서 동기화 된 블록으로 들어갑니다. 큐에서 읽은 요소가 null인지 확인하여 큐가 비어 있음을 확인합니다. 스레드가 잠금을 해제하지만 해당 isAlive 플래그가 아직 false로 설정되지 않았습니다.
  2. 클라이언트 요청이 도착하여 대기열에 메시지를 추가합니다. 수신 메소드는 잠금을 가져 와서 동기화 된 블록으로 들어갑니다. 처리 스레드가 아직 살아 있기 때문에 시작할 필요가 없습니다. 이 메소드는 잠금을 해제합니다.
  3. 처리 스레드가 이제 잠금을 해제하고 종료됩니다.

이 경우 큐에 처리되지 않은 메시지가 하나 있습니다. 이 시나리오가 발생할 수 있습니까? 대담한 문장에서 알 수 있듯이 스레드가 죽기 전에 잠금 장치가 해제 될 수 있습니까?

답변

0

이것은 소비자/생산자 문제입니다. 처리 스레드 (소비자)를 중지/시작할 필요가 없습니다. 차단하고 대기열에있는 메시지를 기다릴 수 있습니다. 클라이언트 스레드 (생성자)가 대기열을 채우고 notify() 소비자 스레드는 차단을 해제하고 메시지를 제거한 후 다시 대기합니다. 다음은 https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html의 예입니다.

+0

하지만 put 메서드는 동기화되어 있으므로 여러 생성자를 사용하려면 차례를 기다려야 할 것이므로 동시 큐의 장점을 잃을 것입니다. 다른 방법이 있습니까? – devil0150

+0

put은 두 생산자가 동시에 대기열에 추가하는 것을 방지하기 위해 동기화되어야하지만 생산자는 대기열이 가득 차면 대기해야합니다. 대기열이 가득 차 있지 않으면 생성자는 해당 메시지를 추가하고 notifyAll을 호출하고 대기하지 않고 종료합니다. –

+0

하지만 두 명의 제작자가 동시에 대기열에 추가 할 수있게하고 싶습니다. 그리고이 경우 두 명의 다른 제작자가 동시에 'put'을 호출하려고하면 그 중 하나는 대기열이 가득차 있지 않아도 다른 하나가 반환하도록 기다려야합니다. – devil0150

관련 문제