2013-03-26 7 views
1

프로그램 내에 Runnable 인스턴스가 여러 개 있다고 가정 해보십시오. 모든 인스턴스는 Executor 인스턴스에 의해 전달됩니다. 또한, 나는 어느 시점에서 이동하기 전에 이러한 실행 파일의 서브 세트가 끝날 때까지 기다릴 필요가 있다고 가정합니다.더 나은 방법으로 스레드에 연결할 수 있습니까?

public abstract class Joinable implements Runnable { 

    private final Semaphore finishedLock = new Semaphore(1); 

    @Override 
    public final void run() { 
     try { 
      finishedLock.acquireUninterruptibly(); 
      doWork(); 
     } finally { 
      finishedLock.release(); 
     } 
    } 

    public abstract void doWork(); 

    public void join() { 
     finishedLock.acquireUninterruptibly(); 
    } 
} 

클래스의 구현에 단순히 실행 중에 수행해야하는지 정의하기 위해, 실행()보다는) doWork을 (대체 할 수 있습니다 :이 할 수있는

한 가지 방법은 다음입니다.

접합 공정은 단순히 다음과 같이 표시됩니다

void doStuff() { 

    Executor executor = Executors.newCachedThreadPool(); 

    List<Joinable> joinables = new LinkedList<Joinable>(); 
    // Fill joinables with implementors of Joinable... 

    List<Runnable> others = new LinkedList<Runnable>(); 
    // Fill others with implementors of Runnable... 

    for(Joinable joinable : joinables) 
     executor.execute(joinable); 

    for(Runnable runnable : others) 
     executor.execute(runnable); 

    for(Joinable joinable : joinables) 
     joinable.join(); 

    // Continue, no matter what the threads in others are up to. 
} 

이이 문제를 (? 그것도 안전) 해결할 수있는 좋은 방법입니다, 또는 더 나은 일이?

답변

2

현재 솔루션은 스레드로부터 안전하지 않습니다. join으로 전화하기 전에 집행자가 Joinablerun로 전화 할 것이라는 보장은 없습니다. 따라서 어떤 경우에는 주 스레드가 Joinable 전에 잠금을 획득합니다.

합계 수인 N을 알고있는 경우 가능한 해결책은 CountDownLatch이고, CountDownLatch(N)을 만들어 각 인스턴스에 전달하십시오. 각 참여가 끝나면 countDown()으로 전화하십시오. 메인 스레드가 걸쇠에 await()을 호출합니다. 나는 단지 같은 파견 실행 가능한 인스턴스의 종류를 가지고 상황을보고 있지 않다 : 래치 카운트가 내가 아는 0

+0

나는 다른 답변도 좋아하지만, 내 프로젝트의 전반적인 디자인과 잘 어울리면서이 답변도 함께했습니다. – csvan

1

이이 문제를 해결하는 좋은 방법 (그것도 안전합니까?)

이 매우 옳지 않다인가. 에 의해 실행중인 Runnable에 가입 할 수 없습니다.

List<Future<?>> futures = new ArrayList<Future<?>>(); 
for(Joinable joinable : joinables) { 
    // this submit returns a `Future`. 
    futures.add(executor.submit(joinable)); 
} 
// submit others to the executor _without_ adding to the futures list 

for (Future<?> future : futures) { 
    // this can throw ExecutionException which wraps exception thrown by task 
    future.get(); 
} 

또는 더 나은 일이있다 : 당신이 목록을 사용하려면 다음과 같은 일을 할? 당신이 기다리고 있었다 경우

모든 작업은 당신이 ExecutorService.awaitTermination(long timeout, TimeUnit unit) 방법을 사용할 수 있습니다 다음 완료합니다. 예를 들면 다음과 같습니다.

executor.awaitTerminate(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 

그러나 작업의 하위 집합을 기다리는 경우 더 좋은 방법은 없습니다.

+0

때까지 await()는 반환하지 않습니다, 불행하게도 나는 문제를 조금 명확히 할 필요가 집행자. 예를 들어 12 가지 인스턴스가 있고 다른 인스턴스는 6 가지 인스턴스라고 가정 해 보겠습니다. 처음 6 명이 끝나기 전에 다른 6 명의 상태가 그때 무엇인지에 관계없이 끝내기를 기다리고 싶다고 말하십시오. 이 경우 나는 awaitTermination을 사용할 수 없다. – csvan

+0

'submit (...) '메소드 @chrsva가 반환 한'Future' 사용법에 대해 더 자세히 설명했습니다. – Gray

관련 문제