2011-05-05 3 views
3

반복자의 원본 데이터를 병렬로 처리 할 수 ​​있도록 여러 스레드에서 동시에 읽을 수있는 반복기를 갖고 싶습니다. 문제는 다른 스레드로 갈 수 있으므로 실제로는 hasNext()을 논리적 인 next()과 연결할 수 없다는 것입니다. (즉, 두 개의 스레드가 hasNext()을 호출 할 수 있으며 각각 하나의 항목 만 있기 때문에 두 번째 스레드가 실패합니다.) 문제는 일부 소스의 경우 실제로 다음 요소가 있는지 알지 못합니다. 그것을 읽으려고 노력하십시오. 그러한 예가 파일에서 행을 읽는 것입니다. 또 하나는 Lucene 색인에서 Term 인스턴스를 읽는 것입니다.일부 소스에서 동시 반복자를 만드는 방법은 무엇입니까?

필자는 반복기 내부에서 큐를 설정하고 별도의 스레드로 큐를 공급할 생각을하고있었습니다. 이렇게하면 hasNext()이 대기열 크기로 구현됩니다. 하지만 그 스레드가 굶어 죽을 수 있기 때문에 대기열이 채워지는 것을 어떻게 보장 할 수 있는지 알지 못합니다.

반복자 계약을 무시하고 NoSuchElementException이 던져 질 때까지 next()을 철저히 호출해야합니까?

문제를보다 세련되게 처리하는 방법이 있습니까?

답변

6

스레드가 Iterator 대신 BlockingQueue에서 가져올 수 있습니까? 이미 알았 듯이 반복자는 동시 액세스에 적합하지 않습니다.

LinkedBlockingQueue를 전달하고 아무 것도 남지 않을 때까지 스레드가 queue.poll()을 수행하게하십시오.

+0

빠른 응답을 보내 주셔서 감사합니다. 이것은 의미가 있지만, 대기열을 채워서 굶어 죽지 않았는지 확인해야합니다. 맞습니까? 잠재적으로 메모리에 들어가기에는 너무 많은 요소가 있기 때문에 모든 요소를 ​​큐에 넣을 수는 없습니다. 나는 큐에 추가로 레코드가 더 이상 큐에 추가되지 않음을 나타내는'AtomicBoolean'을 가져야한다고 생각합니다. –

+0

스레드가 queue.take()를 수행하도록하고, 할 일이 없다는 신호를 보내려면 일종의 poison pill (http://www.javaspecialists.eu/archive/Issue016.html)을 사용할 수 있습니다. – sbridges

+0

두 개 이상의 쓰레드가'take()'를 호출하고 그 중 하나가 poison 알약을 얻는 반면, 두 번째 쓰레드는 빈 큐에 걸리는 것이 가능한가? 이것은'take()'가 메인 쓰레드에서 수행 되어야만하는 값을 작업자 쓰레드로 보내야 함을 의미한다. 또는 나는 무엇인가 놓치고 있냐? –

1

(대부분의) 계약을 유지하고 회피하기위한 하나의 대안/도피가 발생합니다. NoSuchElementExceptions : iterator.next()은 처리 할 수 ​​있지만 하나만있는 맞춤 "End-of-iteration"마커 개체를 반환 할 수 있습니다. 더미. 따라서 하나의 스레드가 hasNext()에 대해 true을 수신하지만 다른 스레드가 이미 마지막 항목을 가져온 경우 첫 번째 스레드는 예외 대신 더미를 가져옵니다.

모든 일반 사용 사례에서이 유형의 반복자를 사용할 수 있어야하며 단일 스레드 사용은 차이점을 알아야합니다. 향상된 for 루프에도 사용할 수 있어야합니다.

더미 항목 때문에 예외가 throw되지 않으므로 hasNext()을 확인하는 대신 NoSuchElementException을 기다리는 경우에만 오류가 발생합니다.

+0

그래, 그걸 큐와 함께 사용한다. 이 경우에 나는 더미가 나타나면 작업자 스레드가 작업을 무시하지만 더미를 다시 대기열에 넣습니다. 그런 식으로 모든 노동자는 결국 그것을 얻습니다. –

-1

내가이 지점을 놓칠 수는 있지만이 상황에서 동기화 된 블록을 사용할 수 없습니까?

synchronized(iterator) 
{ 
    if (iterator.hasNext()) element = iterator.next(); 
} 

여기서 한 스레드가 반복기를 사용할 때 다른 스레드가이 스레드에 액세스 할 수 없습니다.

+0

어떤 경우에는 iterator.next() 메서드가 상당히 많은 작업을 수행하므로 병렬 처리하는 것이 좋습니다. –

관련 문제