2013-01-03 4 views
2

필자는 컬렉션을 보유하고 있으며 해당 요소에 많은 작업을 수행하기 위해 많은 스레드를 생성하려고합니다. 컬렉션의 각 요소는 한 번만 처리해야합니다. 나는 가능한 한 최소한의 동기화를 유지하고 싶은 다음 코드를 내놓았다 :다중 스레드 반복이 안전합니까?

//getting the iterator is actually more complicated in my specific case 
final Iterator it = myCollection.terator(); 
Thread[] threads = new Thread[numThreads]; 

for(int i = 0; i < numThreads; i++) { 
    threads[i] = new Thread(new Runnable() { 
     public void run() { 
      Object obj = null; 
      while(true) { 
       synchronized (it) { 
        if(it.hasNext()) 
         obj = it.next(); 
        else 
         return; 
       } 
       //Do stuff with obj 
      } 
     } 
    }); 
    threads[i].start(); 
} 

for (Thread t : threads) 
    try { 
     t.join(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 

참고 : 어떤 스레드가 이제까지

'OBJ와 함께 물건을'동안 항목을 추가하거나 제거하여 컬렉션을 수정하지 않습니다

이 코드는 사람들이 컬렉션 자체에서 동기화하는 경향이있는 곳에서 발견 된 예제와 완전히 다르며 Collection.synchronizedStuff..을 사용하거나 전체 반복에 대해 동기화합니다. 내 연구 동안 나는 ThreadPoolExecutor을 사용하여 구현 된 더 나은 대안을 찾았지 만 잠시 잊어 버리자 ...

위의 코드 1을 위의 코드는 안전합니까? 그렇지 않다면, 왜?

+1

메모 1이 사실로 유지되는 한 괜찮을 것입니다. 집행자는 확실히 이런 식으로 갈 길입니다. – BevynQ

+0

성능상의 이유로'synchronized' 블록을 작게 유지하려고한다면, (네이티브) 각 쓰레드를 생성하고 실행하는 동안 얼마나 많은 시간이 소요되는지, 그리고 제안 된대로 executor를 사용하는 것이 놀랄 것입니다. –

+0

개념 코드가 정상적으로 보입니다. 잘 작동해야합니다. 반복자에 대한 액세스 (객체 검사 및 읽기 포함)가 동기화되므로 아무런 문제가 발생하지 않습니다. – xagyg

답변

5

전혀 동기화를 사용하지 않습니다.

ExecutorService에 작업을 추가하는 루프가 있습니다.

ExecutorService es = Executors.newFixedThreadPool(nThreads); 

for(final MyType mt: myCollection) 
    es.submit(new Runnable() { 
     public void run() { 
      doStuffWith(mt); 
     } 
    }); 
es.shutdown(); 
es.awaitTermination(1, TimeUnit.HOURS); 

스레드 풀을 만들고 종료해야하는 필요성을 제거하면 스레드 풀이 더 짧아집니다.

+0

당신의 mycollection이 변경되지 않으면 작동 할 것이라고 나는 믿는다. –

+0

이것은 영리한 생각입니다 각 항목에 다른 스레드를 첨부하십시오 ... – JasonHuang

0

가 나는 myCollection 최종 확인하고 각각에 대한-그래서 synchronziation이 필요하지 않습니다 각 스레드의 새로운 반복자를 생성

public void run() { 
     Object obj = null; 
     for (Object e : myCollection) { 
      obj = e; 
     } 

으로 코드를 변경하는 것이 더 나은 것 같아요.

+0

hmmm ...이 코드를 사용하면 각 객체가 컬렉션의 모든 객체에 대해 작업을 수행하지만 각 객체는 한 번만 조작해야합니다. 또한 향상된 for 루프는 내부적으로 iterator를 사용하며 (hasNext() 및 next()) 호출해야하며 동기화하지 않으면 코드가 손상 될 수 있습니다. – Gevorg

+0

모든 스레드에 대해 반복자를 만들면 좋은 아이디어라고 생각하지 않습니다. 자원 낭비 때문에 많은 오버 헤드가 발생합니다. – JasonHuang

관련 문제