2014-01-11 3 views
6

나는 ExecutorService를 사용하여 큐에 대기하는 일련의 작업을 가지고있다. 사용자가 '취소'를 클릭하면 최대한 빨리 중단해야하는 작업을 알릴 필요가 있습니다. 그러나 때로는 부모 스레드가 진행되기 전에 완료해야하는 중요한 코드 섹션에 있습니다. 어떻게해야합니까? 나는 자기 자신의 취소 플래그를 사용하고 싶지는 않습니다. 왜냐하면 sleep/wait가 끝나지 않기 때문입니다. 미래를 방해하지만 어떻게 끝나기를 기다리는가?

는이 코드가 작동 것이라고 생각하지만, 내가하고 싶은 일을하지 않습니다

"가능한 한 빨리"
while(true) { 
    //Do this in a loop. If our thread is interrupted, we call cancel on the threads (to try to get them to hurry up by skipping non-essential stuff), but we still need to wait for them to finish. 
    try { 
     for(Future<Void> future : futures) { 
      future.get(); //I thought that this would continue waiting, even if I call cancel, but it doesn't. How can I wait for the future to finish? 
     } 
     break; //OK, everything is finished, exit the wait loop. 
    } catch(InterruptedException e) { 
     wasInterrupted = true; //We'll rethrow the exception laster as an AbortException. 
     //Need to wait for futures to finish, even if it's canceled. 
     log.info("Attempting to interrupt threads that are reading changes..."); 
     for(Future<Void> future : futures) { 
      future.cancel(true); //I want to tell the threads to 'hurry up' and skip non-essential stuff. 
     } 
    } catch(ExecutionException e) { 
     throw e.getCause(); 
    } 
} 

//I shouldn't get to this line until all futures have finished! 

답변

4

어떻게 미래를 방해하지만 끝내기를 기다리나요?

흥미로운 문제. 발견 한대로 Future을 취소하면 CancellationException이 던져 지므로 get()에 다시 전화 할 수 없기 때문에 코드가 작동하지 않습니다.

나는 당신의 요구 사항을 이해하고있는 경우 : 당신은 여전히를 얻을 수 있기를 원하는

당신은 sleep, wait을 중지 할 때문에 스레드를 중단 할 수 있어야합니다
  • , 등
  • 을 취소 된 작업의 결과 할 수있는 일에

Future의 여기 하지 사용하는 것입니다. 대신 자신의 작업 래퍼를 ​​사용하고 executorService.awaitTermination(...)으로 끝내기 위해 ExecutorService 자체를 기다릴 수 있습니다.

작업 결과가 필요한 경우 Runnable 래퍼 클래스는 계산 결과를 보유하고 boolean done 플래그를 갖습니다. 대기중인 스레드는 플래그가 true로 설정되도록 각 Runnable을 기다립니다. 래퍼가 run() 메서드를 완료하면 donenotify()을 자체적으로 설정합니다. finally 블록에서 그렇게해야합니다.

대기중인 스레드가 인터럽트되면 executorService.shutdownNow(true)을 호출하여 모든 스레드를 인터럽트하지만 완료 될 때까지 기다리는 루프를 계속합니다.

이런 식으로.

+0

훌륭한 솔루션입니다. 나는 executorService.awaitTermination() 메소드에 대해 몰랐다. 그게 내가 원하는거야. –

+0

그러나 자신의 작업 래퍼 사용에 대한 부분을 이해하지 못합니다.제 경우에는 결과가 필요 없습니다. 스레드가 끝날 때까지 기다릴 필요가 있습니다. 그래서 이것은 저에게 영향을주지 않습니다. 그러나 Future 객체를 사용하지 않고 ExecutorService를 사용하는 방법이 궁금합니다. 그 작업을 제출하는 유일한 API가 아닌가요? –

+0

결과가 필요 없다면 훨씬 간단합니다. 'submit (...) '을 호출하면'Future'가되지만'void'를 반환하고'FutureTask' @ JesseBarnum을 생성하지 않는'execute (...)'를 호출 할 수도 있습니다. – Gray

0

어쨌든

를 종료 할 때 스레드가, 당신을 알고해야 함을 의미 인터럽트 스레드 정책을 사용할 수 있습니다

if (Thread.interrupted()) // Clears interrupted status! 
     throw new InterruptedException(); 

,299,354,815 참조

+3

작업자 스레드는 종료 시점을 알고 있습니다. 문제는 부모 스레드가 Future.get()이 취소가 일단 호출되면 차단하지 않기 때문에 대기 시간을 알 수 없다는 것입니다. –

관련 문제