001 package com.croftsoft.core.util; 002 003 import java.util.Timer; 004 import java.util.TimerTask; 005 006 import com.croftsoft.core.lang.lifecycle.Lifecycle; 007 import com.croftsoft.core.lang.NullArgumentException; 008 009 /********************************************************************* 010 * Runs tasks periodically. 011 * 012 * @version 013 * 2002-02-27 014 * @since 015 * 2001-03-06 016 * @author 017 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 018 *********************************************************************/ 019 020 public final class Metronome 021 implements Lifecycle 022 ////////////////////////////////////////////////////////////////////// 023 ////////////////////////////////////////////////////////////////////// 024 { 025 026 private Runnable runnable; 027 028 private long periodInMilliseconds; 029 030 private final boolean useDaemonThread; 031 032 private boolean isStarted = false; 033 034 private Timer timer; 035 036 private TimerTask timerTask; 037 038 ////////////////////////////////////////////////////////////////////// 039 ////////////////////////////////////////////////////////////////////// 040 041 public Metronome ( 042 Runnable runnable, 043 long periodInMilliseconds, 044 boolean useDaemonThread ) 045 ////////////////////////////////////////////////////////////////////// 046 { 047 NullArgumentException.check ( this.runnable = runnable ); 048 049 this.periodInMilliseconds = periodInMilliseconds; 050 051 this.useDaemonThread = useDaemonThread; 052 053 if ( periodInMilliseconds < 0 ) 054 { 055 throw new IllegalArgumentException ( 056 "periodInMilliseconds < 0 " ); 057 } 058 } 059 060 ////////////////////////////////////////////////////////////////////// 061 ////////////////////////////////////////////////////////////////////// 062 063 public synchronized void resetPeriodInMilliseconds ( 064 long periodInMilliseconds ) 065 ////////////////////////////////////////////////////////////////////// 066 { 067 if ( periodInMilliseconds < 0 ) 068 { 069 throw new IllegalArgumentException ( 070 "periodInMilliseconds < 0 " ); 071 } 072 073 this.periodInMilliseconds = periodInMilliseconds; 074 075 if ( isStarted ) 076 { 077 stop ( ); 078 079 start ( ); 080 } 081 } 082 083 public synchronized void resetRunnable ( Runnable runnable ) 084 ////////////////////////////////////////////////////////////////////// 085 { 086 NullArgumentException.check ( this.runnable = runnable ); 087 088 if ( isStarted ) 089 { 090 stop ( ); 091 092 start ( ); 093 } 094 } 095 096 ////////////////////////////////////////////////////////////////////// 097 ////////////////////////////////////////////////////////////////////// 098 099 public synchronized void init ( ) 100 ////////////////////////////////////////////////////////////////////// 101 { 102 timer = new Timer ( useDaemonThread ); 103 } 104 105 public synchronized void start ( ) 106 ////////////////////////////////////////////////////////////////////// 107 { 108 isStarted = true; 109 110 timerTask = new TimerTask ( ) { 111 public void run ( ) { runnable.run ( ); } }; 112 113 // schedule() seems to max out at just under 20 tasks per second. 114 // Possibly due to a 50 ms system clock resolution? 115 116 timer.schedule ( timerTask, 0, periodInMilliseconds ); 117 } 118 119 public synchronized void stop ( ) 120 ////////////////////////////////////////////////////////////////////// 121 { 122 isStarted = false; 123 124 if ( timerTask != null ) 125 { 126 timerTask.cancel ( ); 127 } 128 129 timerTask = null; 130 } 131 132 public synchronized void destroy ( ) 133 ////////////////////////////////////////////////////////////////////// 134 { 135 stop ( ); 136 137 try 138 { 139 if ( timer != null ) 140 { 141 timer.cancel ( ); 142 } 143 } 144 catch ( Exception ex ) 145 { 146 ex.printStackTrace ( ); 147 } 148 149 timer = null; 150 151 runnable = null; 152 } 153 154 ////////////////////////////////////////////////////////////////////// 155 ////////////////////////////////////////////////////////////////////// 156 }