001package jmri.jmrit.logixng.util; 002 003import java.util.TimerTask; 004 005/** 006 * A timer task that can be stopped, and there the stop method waits until the 007 * task is finished. 008 * <p> 009 * Note that this class does [u]not[/u] work for repeating timers. The class 010 * can be used for tasks that are scheduled over and over again, but only works 011 * for one shoot timer. 012 * <p> 013 * In other words, the class works for TimerUtil.schedule(@Nonnull TimerTask task, long delay) 014 * but not for TimerUtil.schedule(@Nonnull TimerTask task, long delay, long period). 015 * This is due to how the method TimerTask.cancel() works. 016 */ 017public abstract class ProtectedTimerTask extends TimerTask { 018 019 private final Object _lock = new Object(); 020 private boolean _timerIsRunning = false; 021 private boolean _stopTimer = false; 022 023 public abstract void execute(); 024 025 @Override 026 public final void run() { 027 synchronized(_lock) { 028 if (_stopTimer) return; 029 _timerIsRunning = true; 030 } 031 032 // Execute the task 033 execute(); 034 035 synchronized(_lock) { 036 _timerIsRunning = false; 037 } 038 } 039 040 /** 041 * Stop the timer. 042 * This method will not return until the timer task is cancelled and stopped. 043 * This code ensures that we don't return from this method until the timer 044 * task is cancelled and that it's not running any more. 045 */ 046// @SuppressWarnings(value = "SleepWhileInLoop") 047 public void stopTimer() { 048 synchronized (_lock) { 049 _stopTimer = true; 050 // If cancel() returns true, the task will never be 051 // executed and we are done. 052 if (cancel()) return; 053 // If the timer task is not running, we don't have 054 // to wait for it to finish. 055 if (!_timerIsRunning) { 056 return; 057 } 058 } 059 // Try max 50 times 060 for (int count=0; count <= 50; count++) { 061 synchronized (_lock) { 062 if (!_timerIsRunning) return; 063 } 064 try { 065 Thread.sleep(20); 066 } catch (InterruptedException e) { 067 Thread.currentThread().interrupt(); 068 } 069 } 070 throw new RuntimeException("Cannot stop timer"); 071 } 072 073}