2016-07-08 3 views
1

나는이 작업을 수행하는 방법을 확실하지 오전 작업을 수행, 나는 i 번째 항목을 제거하고 그 위에 몇 가지 코드를 수행의 ConcurrentLinkedQueue (그것 모두)를 반복하고 싶습니다.자바 스트림은 제거하고 ConcurrentLinkedQueue를

public static class Input { 

    public static final ConcurrentLinkedQueue<TreeNode> treeNodes = new ConcurrentLinkedQueue<>(); 
} 

public static class Current { 

    public static final ConcurrentHashMap<Integer, TreeNode> treeNodes = new ConcurrentHashMap<>(); 
} 

TreeNode이 간단한 클래스

TreeNode treeNode = Input.treeNodes.poll(); 

    while (treeNode != null) { 

     treeNode.init(gl3); 

     Current.treeNodes.put(treeNode.getId(), treeNode); 

     treeNode = Input.treeNodes.poll(); 
    } 

입니다 이것은 내가 사용 스트림 할 노력하고 있어요 방법은 다음과 같습니다 :

Input.treeNodes.stream() 
      .forEach(treeNode -> { 
       Input.treeNodes.remove(treeNode); 
       treeNode.init(gl3); 
       Current.treeNodes.put(treeNode.getId(), treeNode); 
      }); 

내가 할하는 데 사용 된 것입니다 안에있는 항목을 제거해야 할 때 오류가 발생할 수 있습니다. forEach 동작.

그래서 제 질문은 :

이 안전한 및/또는 그것을 할 수있는 더 나은 방법이있다? 스트림을 처리하는 동안 당신이 얻을 수 있기 때문에

당신이 가정 한 것처럼
+1

HashMap (코드에서 뭔가를 이름 짓기 위해 기존 JDK 클래스를 재사용하는 것은 좋은 생각처럼 보이지 않습니다.), Input, TreeNode 등은 무엇입니까? [mcve]를 제작할 수 있습니까? – assylias

+0

물론, 나는 나의 질문을 편집했다. 어떤 이름을 언급하고 있습니까? – elect

+1

JDK에는 HashMap이 있고 자신 만의 클래스 인 HashMap 역시 너무 혼란 스럽다. – assylias

답변

2

, 당신은 기가되는 콜렉션을 수정해서는 안 아주 명확하지 않다 반면에

(단지 for(Object o:objectArray){} 루프에서와 같이) ConcurrentModificationException하는 TreeNode 현재의 경우처럼 List에서 모든 요소를 ​​제거하려는 경우 겉으로는 일부 작업을 수행하여 Map에 넣으려고합니다.

안전하게 통해 현재의 논리를 달성 할 수

Input.treeNodes.stream() 
     .map(treeNode -> { 
      treeNode.init(gl3); 
      Current.treeNodes.put(treeNode.getId(), treeNode); 
     }); 
Input.treeNodes.clear(); 
+0

'Input.treeNodes'의 각'TreeNode' 엘리먼트에 대해'poll()'으로 제거하고,'init()'메소드를 호출하여 동시 hashMap에 추가합니다.'Current .treeNodes' – elect

+0

정확하게, 모두 poll()'concurrentLinkedQueue'라고 생각하고'while'으로 루핑하는 것은 충분합니다. 어쨌든, thanks – elect

+0

제안 된 솔루션은' while 루프' – Matyas

2

이 문제가 Stream의 구축에 사용 된 Spliterator에 의해 결정됩니다. ConcurrentLinkedQueue.spliterator()의 문서 내용 :

이 대기열의 요소에 대해 Spliterator을 반환합니다.
반환 된 스플 리터레이터는 weakly consistent입니다.

"weakly consistent"는 의미 : 자신의 반복자와 Spliterators이 약 일관성보다는 빨리 실패 순회를 제공한다는 점에서 (대부분의 Queue를 포함한다)

대부분의 동시 컬렉션 구현은 또한 일반적인 java.util 규칙과 다를 :

  • 가 다른 작업
  • 을과 동시에 진행될 수있다 0
  • 그들은 결코 던지지 않을 것입니다. ConcurrentModificationException
  • 구성시 정확히 존재했던대로 요소를 통과하는 것이 보장되며, 공사 이후의 수정 사항을 반영 할 수는 있지만 보장 할 수는 없습니다.

이것은 영향을받은 요소를 제거해도 아무런 영향이 없어야 함을 의미합니다.

다른 스레드가 요소를 추가하거나 제거 할 때 이러한 요소와 관련된 Stream 작업의 결과는 예측할 수 없습니다.

그러나 에 대해서는 remove(Object)이 의도 된 사용 사례가 아니어야합니다.

+0

'Input.treeNodes'는 나중에 OpenGL 스레드에 의해 초기화 될 필요가있는 리소스에 대한 쓰레드 안전 입력 포인트이기 때문에, 어떤 구조를 제안합니까? 동시 Arraylist? 왜냐하면 나는 [여기] (http://stackoverflow.com/questions/6916385/is-there-a-concurrent-list-in-javas-jdk)에서 concurrentLinkedQueue를 사용하는 아이디어를 얻었 기 때문에 – elect

+2

나는 그것을 사용하지 않을 것이라고 생각한다. 이 사용 사례의 경우에도 큐가 잘못되었습니다. 즉, 헤드에서 제거 할 때 대기열의 의도 된 사용 사례 인 제거 및 처리를 원합니다. 그러나 이것을하는'Stream'을 만드는 것은 까다 롭습니다. Java 9에서는'Stream.generate (queue :: poll) .takeWhile (Objects :: nonNull)'을 사용할 수 있습니다. 하지만 Java 8에서는 이와 동등한 루프를 사용합니다. – Holger

+0

흥미 롭다면, 나는 고려할 것이다. 고마워. – elect

관련 문제