2017-12-18 28 views
0

나는 라이브 소켓을 얻기 위해 동시에 여러 스레드에 의해 호출되는 아래 메소드를 가지고있다. 매개 변수로 LinkedBlockingQueue을 취한 다음 사용 가능한 liveSocket이 있는지 반복하고 볼 수 있습니다. 사용 가능한 경우 소켓을 제거한 다음 반환합니다.LinkedBlockingQueue에서 elments를 제거하는 동안 아래 코드가 안전합니까?

private Optional<Holder> getSocket(final LinkedBlockingQueue<Holder> endPoints) { 
    Optional<Holder> liveSocket = Optional.absent(); 
    if (!endPoints.isEmpty()) { 
     for (Holder state : endPoints) { 
     // check if socket is live? if yes then remove and return that. 
     if (state.isLive()) { 
      liveSocket = Optional.of(state); 
      endPoints.remove(state); 
      return liveSocket; 
     } 
     } 
    } 
    return Optional.absent(); 
    } 

위의 코드가 스레드로부터 안전한지 여부를 확인하고 싶습니까? 여기서 Holder은 변경 불가능한 클래스입니다.

+0

큐 연산 스레드 안전하지만 포함 된 개체의 상태가 아니다. 'liveSocket'이 상태를 검사 할 때와 큐에서 제거 할 때 사이에 다른 스레드에 의해 non-live가되면 어떻게됩니까? –

답변

1

대기열 조작 작업은 스레드로부터 안전하므로 remove()ConcurrentModificationException을 반환하지 않습니다. 그러나 큐에 포함 된 개체의 상태를 중심으로 스레드 안전 문제가 있습니다.

Holder 개체의 "실시간"상태를 확인하고 대기열에서 제거 할 때까지 경쟁 조건이 있습니다. 다른 스레드는 동일한 코드에서 동시에 실행될 수 있으며 두 스레드가 동일한 객체를 사용하게 될 가능성이 높습니다. 어떤 스레드가 remove()에 마지막으로 전화를 걸면 false이 반환되지만 결과를 조사하지 않으므로 알 수 없습니다. 두 스레드는 모두 동일한 객체를 사용하려고합니다.

검색/제거 작업을 동기화해야합니다.

호기심를 들어, 여기에 내가 ConcurrentModificationExceptionLinkedBlockingQueue 발생하지 않는 것을 보여주기 위해 사용되는 코드입니다 :

public static void main(String[] args) throws Exception 
{ 
    String[] data = { "a", "b", "c", "d", "e", "f","g" }; 
    LinkedBlockingQueue<String> lb = new LinkedBlockingQueue<>(Arrays.asList(data)); 

    new Thread(() -> 
    { 
     try 
     { 
      Thread.sleep(2000); 
      lb.add("x"); 
      System.out.println("added"); 
      Thread.sleep(1000); 
      lb.remove("e"); 
      System.out.println("removed"); 
     } 
     catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 
    }).start(); 

    for (String s : lb) 
    { 
     System.out.println(s); 
     Thread.sleep(1000); 
    } 
} 

당신이 LinkedBlockingQueue에 대한 LinkedList을 대체 할 경우 예상대로 ConcurrentModificationException를 얻을.

출력 :

a 
b 
added 
c 
removed 
d 
f 
g 
x 
-1

이것은 스레드로부터 안전하지 않을뿐만 아니라 단일 스레드 내에서도 잘못되었습니다. remove()ConcurrentModificationException이 표시됩니다. 명시적인 Iterator을 사용해야하고 Iterator을 통해 삭제해야합니다.

그리고 여러 스레드를 통해 정확성을 위해 루프 주변에 동기화 또는 세마포어가 필요합니다.

NB isEmpty() 테스트는 무의미합니다. 반복은 이미 확인해야합니다. 개를 지키고 짖지 마라.

+0

실제로 제거 작업은 정상적으로 작동하며'LinkedBlockingQueue'가있는 CME가 없습니다 (일반 'LinkedList'와는 대조적 임). Javadoc에서 설명한 것처럼'java.util.concurrent' 컬렉션은 thread로부터 안전합니다. 그러나 큐에 포함 된 개체 주변에 스레드 안전 문제가 있습니다. –