문제

나는 현재 Futuretasks와 Executors를 사용하여 멀티 스레드 환경에서 불쾌한 버그를 사냥하고 있습니다. 기본 아이디어는 고정 된 수의 스레드가 AA 테이블에 표시 될 결과를 계산하는 개별 FutureTask를 실행하도록하는 것입니다 (GUI 측면을 여기에 신경 쓰지 마십시오).

나는 이것을 오랫동안보고 있었다. 나는 내 정신을 의심하기 시작했다.

이 코드를 고려하십시오.

public class MyTask extends FutureTask<Result> {
   private String cellId;
   ...
   protected void done() {
      if (isCancelled()) return;
      try {
          Result r = get(); // should not wait, because we are done
          ... // some processing with r
          sendMessage(cellId, r);
      } catch (ExecutionException e) { // thrown from get
         ... 
      } catch (InterruptedException e) { // thrown from get
         ... 
      }
   }
   ...
}

언제 done() Mytask 인스턴스를 처리하는 집행자가 호출합니다. 작업이 취소되었으므로 도착했는지 확인합니다. 그렇다면 나머지 활동을 모두 건너 뜁니다. 특히 전화하지 않습니다. sendMessage().

futuretask.done ()에 대한 문서는 다음과 같이 말합니다.

이 작업이 상태 ISDON (일반적으로 또는 취소를 통해)으로 전환 할 때 보호 된 방법이 호출되었습니다. 기본 구현은 아무것도하지 않습니다. 서브 클래스는이 메소드를 무시하여 완료 콜백을 호출하거나 부기를 수행 할 수 있습니다. 이 방법의 구현 내에서 상태를 쿼리 하여이 작업이 취소되었는지 여부를 결정할 수 있습니다. (API 참조)

그러나 내가 문서에서 얻지 못하는 것 FutureTask 의미론입니다 동안 done() 실행 중입니다. 내가 통과한다면 어떨까요? isCancelled() 처음에 확인하지만 바로 그 직후에 다른 스레드는 cancel() 방법? 내 임무가 마음을 바꾸고 대답하게 할 것인가 isCancelled() == true 그때부터?

그렇다면 메시지가 전송되었는지 나중에 어떻게 알 수 있습니까? 보고 있습니다 isDone() 작업 실행이 완료되었다고 말하지만 isCancelled() 그때도 사실이었고, 메시지를 제 시간에 보내야하는지 알 수 없었습니다.

어쩌면 이것은 분명하지만 지금은 실제로 그것을 보지 못합니다.

도움이 되었습니까?

해결책

API에서 (강조 광산) :

공개 부울 취소 (부울 Mayinterruptifrunning)

인터페이스에서 복사 한 설명 : 미래

이 작업의 실행을 취소하려고 시도합니다. 작업이 이미 완료되면이 시도가 실패합니다., 이미 취소되었거나 다른 이유로 취소 할 수 없습니다.

따라서 FutureTask는 ISDONE 단계로 전환했을 때 작업을 취소 할 수 없다는 가정을 제외하고 있습니다.

다른 팁

FutureTask#done() 주어진 인스턴스에 대해 한 번 이상이라고 불리며 한 가지 이유 만 요구됩니다. run() 오류의 유무에 관계없이 완료되었습니다 cancel() 앞의 이벤트 중 하나가 발생하기 전에 실행되었습니다. 이러한 결과 중 하나에 의한 완료 기록은 다음과 같습니다. 래칭. 이유 a FutureTask "동시에"경쟁하는 이벤트에 관계없이 완성 된 것은 변경 될 수 없습니다.

따라서 내부 FutureTask#done() 중 하나만 isCancelled() 또는 isDone() 그때와 영원히 더 많은 것을 돌려 줄 것입니다. 구별하기가 어렵습니다 isDone() 오류 또는 성공적인 완료 방식으로 True보고. 당신은 무시할 수 없습니다 set() 또는 setException(Throwable) 결정적으로, 둘 다 내부 대표로 AQS 여부를 결정합니다 시도 값의 성공적인 수확량을 기록하거나 예외를 만나면 예외가 발생해야합니다. 두 가지 방법을 우선적으로 사용하면 호출되었음을 알 수 있지만 기본 구현의 결정을 관찰 할 수는 없습니다. 두 이벤트 중 하나가 "너무 늦게"발생하는 경우 —SAY, ~ 후에 취소 - 값을 기록하려는 시도 또는 예외는 무시됩니다.

구현을 연구하면서, 오류로부터 불확실한 성공적인 결과를 식별하는 유일한 방법은 총알을 물고 전화하는 것입니다. get().

결과를 바탕으로 작업의 "외부"메시지를 보내지 않겠습니까? 미래u003CV> 객체가 반환했습니다 ExecutorService? 이 패턴을 사용했는데 잘 작동하는 것 같습니다. 호출 가능u003CV> an을 통한 작업 ExecutorService. 그런 다음 각 기본 작업에 대해 대기하는 보조 작업을 제출하십시오. 미래u003CV> 기본 작업 중에서 미래u003CV> 기본 작업이 성공적으로 완료되었음을 나타냅니다. 이 접근법에는 추측이 없습니다. 전화 할 때 미래u003CV> .가져 오기() 반품, 당신은 버전을 호출하지 않는 한 작업이 터미널 상태에 도달했음을 보장합니다. 가져 오기 시간 초과 논쟁이 필요합니다.

이 접근법을 취하면 두 개의 별도를 사용해야합니다. ExecutorService 인스턴스 : 하나는 1 차 작업과 2 차 작업을위한 것입니다. 이것은 교착 상태를 방지하기위한 것입니다. 2 차 작업이 시작되어 스레드 풀 크기가 제한 될 때 시작부터 1 차 작업을 시작하는 것을 원하지 않습니다.

확장 할 필요가 없습니다 FutureTasku003CV> 조금도. 작업을 그대로 구현하십시오 호출 가능u003CV> 사물. 그러나 어떤 이유로 어떤 이유로 작업이 취소되었는지 감지하려는 경우 호출 가능u003CV> 코드, 스레드의 인터럽트 상태를 확인하십시오. Thread.terrupted ().

나는 당신이 전화 할 수있는 작은 테스트 케이스를 작성하는 것이 좋습니다. cancel() 당신의 동안 Future 인스턴스가 매달려 있습니다 done() 그리고 무슨 일이 일어나는지보십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top