5

제 독서에서 ScheduledExecutorService는 Java에서 타이머를 시작하고 중지하는 올바른 방법입니다.ScheduledExecutorService를 사용하여 타이머를 시작 및 중지

타이머를 시작하고 중지하는 코드를 포트해야합니다. 이것은주기적인 타이머가 아닙니다. 이 코드는 타이머를 시작하기 전에 타이머를 중지합니다. 그래서, 모든 시작은 실제로 재시작()입니다. ScheduledExecutorService를 사용하여이 작업을 수행 할 올바른 방법을 찾고 있습니다. 여기에 내가 생각해 낸 것이있다. 일 내가 놓친 거지에 대한 의견과 통찰력을 찾고 :

ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(1); 
ScheduledFuture<?> _TimerFuture = null; 

private boolean startTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, do not interrupt it. 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private boolean stopTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, interrupt it here. 
      _TimerFuture.cancel(true); 
     } 

     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private class TimerPopTask implements Runnable { 
    public void run() { 
     TimerPopped(); 
    } 
} 

public void TimerPopped() { 
    //Do Something 
} 

TIA, 루블

이 문제처럼 보인다
+0

코드 작성된대로 컴파일되지 않습니다. startTimer()의 _batchTimer가 어디에도 선언되어 있지 않습니다. startTimer 및 stopTimer의 반환 값은 무엇입니까? 예상되는 동작에 대해 좀 더 자세히 설명하면 도움이 될 것입니다. 왜 start/stopTimer가 잠재적으로 호출을 막고 싶습니까? – Sbodd

+0

@Sbodd, 타이머를 시작하려고 할 때 이미 타이머가 실행중인 경우이를 중지하고 동시에 두 개의 타이머가 터지지 않도록해야합니다. get() 대신에 cancel()을 호출해야합니다. – rouble

답변

3

:

당신의 취소 거짓을 전달하는 때문에
private boolean startTimer() { 
    // ...... 
     if (_TimerFuture != null) { 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
    // ...... 
} 

작업이 이미 실행중인 경우 이전 _TimerFuture이 취소되지 않을 수 있습니다. 어쨌든 새로운 하나가 생성됩니다 (그러나 ExecutorService은 고정 된 스레드 풀 크기가 1이기 때문에 동시에 실행되지 않습니다). 어쨌든 startTimer()가 호출 될 때 타이머를 다시 시작할 때의 원하는 동작처럼 들리지는 않습니다.

나는 약간을 재 설계 할 것이다. 나는 TimerPopTask 인스턴스는 "취소"는 일이 될 만들 것, 그리고 나는 그들이이 생성되면 혼자 ScheduledFutures을 떠날 것이다 :가 startTimer를

private class TimerPopTask implements Runnable { 
    //volatile for thread-safety 
    private volatile boolean isActive = true; 
    public void run() { 
     if (isActive){ 
      TimerPopped(); 
     } 
    } 
    public void deactivate(){ 
     isActive = false; 
    } 
} 

그때 차라리 ScheduledFuture의 인스턴스보다 TimerPopTask의 인스턴스를 유지하는 것입니다 및 재 배열 thusly 히 방법 :

private TimerPopTask timerPopTask; 

private boolean startTimer() { 
    try { 
     if (timerPopTask != null) { 
      timerPopTask.deactivate(); 
     } 

     timerPopTask = new TimerPopTask(); 
     _Timer.schedule(timerPopTask, 
         TIMER_IN_SECONDS, 
         TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

(.하는 stopTimer와 마찬가지로 수정() 메소드)

당신은 당신이 진정으로 태어나 셨 예상되는 경우 스레드의 수를 크랭크 할 수 있습니다 딩은 '다시 시작'에 타이머가 현재의 타이머가 만료되기 전에 :

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5); 

당신은 내가 설명하고 또한 현재의 ScheduledFuture에로 현재 TimerPopTask 모두에 대한 참조를 유지, 하이브리드 접근 방식으로 가고 싶은 최고의 만들 수 있습니다 노력을 취소하고 가능하면 스레드를 무료로, 취소가 보장되지 않는다는 것을 이해합니다.

(참고 :..이 모두가 그렇지 않으면 추가 안전 장치가 필요합니다가 startTimer()와하는 stopTimer을() 메서드 호출이 하나의 메인 스레드에 국한되며, 단지 TimerPopTask 인스턴스 스레드간에 공유되는 가정)

+0

좋은 지적. 작업을 실행 중이라고 가정 해 봅시다. 새 작업이 만들어지고 TIMER_IN_SECONDS 초 후에 실행되도록 예약됩니다. 이 시간 (TIMER_IN_SECONDS 초)은 언제 시작됩니까? schedule()이 호출되거나 스레드 풀에 사용 가능한 스레드가있을 때 시작됩니까? – rouble

+0

TIMER_IN_SECONDS 지연은 schedule()이 호출 될 때 바로 시작됩니다.작업은 지연보다 빨리 시작되도록 보장되지만 나중에 스레드 가용성에 따라 일부 시작될 수 있습니다. ScheduledThreadPoolExecutor의 javadoc에서 : "지연된 작업은 활성화 된 것보다 빨리 실행되지만 활성화 된 후에는 실시간 보장이 없습니다." –

관련 문제