15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 import java.util.Date; 28 import java.util.concurrent.atomic.AtomicInteger; 29 30 /** 31 * A facility for threads to schedule tasks for future execution in a 32 * background thread. Tasks may be scheduled for one-time execution, or for 33 * repeated execution at regular intervals. 34 * 35 * <p>Corresponding to each <tt>Timer</tt> object is a single background 36 * thread that is used to execute all of the timer's tasks, sequentially. 37 * Timer tasks should complete quickly. If a timer task takes excessive time 38 * to complete, it "hogs" the timer's task execution thread. This can, in 39 * turn, delay the execution of subsequent tasks, which may "bunch up" and 40 * execute in rapid succession when (and if) the offending task finally 41 * completes. 42 * 43 * <p>After the last live reference to a <tt>Timer</tt> object goes away 44 * <i>and</i> all outstanding tasks have completed execution, the timer's task 45 * execution thread terminates gracefully (and becomes subject to garbage 46 * collection). However, this can take arbitrarily long to occur. By 47 * default, the task execution thread does not run as a <i>daemon thread</i>, 48 * so it is capable of keeping an application from terminating. If a caller 49 * wants to terminate a timer's task execution thread rapidly, the caller 50 * should invoke the timer's <tt>cancel</tt> method. 51 * 52 * <p>If the timer's task execution thread terminates unexpectedly, for 53 * example, because its <tt>stop</tt> method is invoked, any further 54 * attempt to schedule a task on the timer will result in an 55 * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt> 56 * method had been invoked. 57 * 58 * <p>This class is thread-safe: multiple threads can share a single 59 * <tt>Timer</tt> object without the need for external synchronization. 60 * 61 * <p>This class does <i>not</i> offer real-time guarantees: it schedules 62 * tasks using the <tt>Object.wait(long)</tt> method. 63 * 64 * <p>Java 5.0 introduced the {@code java.util.concurrent} package and 65 * one of the concurrency utilities therein is the {@link 66 * java.util.concurrent.ScheduledThreadPoolExecutor 67 * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly 68 * executing tasks at a given rate or delay. It is effectively a more 69 * versatile replacement for the {@code Timer}/{@code TimerTask} 70 * combination, as it allows multiple service threads, accepts various 71 * time units, and doesn't require subclassing {@code TimerTask} (just 72 * implement {@code Runnable}). Configuring {@code 73 * ScheduledThreadPoolExecutor} with one thread makes it equivalent to 74 * {@code Timer}. 75 * 76 * <p>Implementation note: This class scales to large numbers of concurrently 77 * scheduled tasks (thousands should present no problem). Internally, 78 * it uses a binary heap to represent its task queue, so the cost to schedule 79 * a task is O(log n), where n is the number of concurrently scheduled tasks. 80 * 81 * <p>Implementation note: All constructors start a timer thread. 82 * 164 * Creates a new timer whose associated thread has the specified name, 165 * and may be specified to 166 * {@linkplain Thread#setDaemon run as a daemon}. 167 * 168 * @param name the name of the associated thread 169 * @param isDaemon true if the associated thread should run as a daemon 170 * @throws NullPointerException if {@code name} is null 171 * @since 1.5 172 */ 173 public Timer(String name, boolean isDaemon) { 174 thread.setName(name); 175 thread.setDaemon(isDaemon); 176 thread.start(); 177 } 178 179 /** 180 * Schedules the specified task for execution after the specified delay. 181 * 182 * @param task task to be scheduled. 183 * @param delay delay in milliseconds before task is to be executed. 184 * @throws IllegalArgumentException if <tt>delay</tt> is negative, or 185 * <tt>delay + System.currentTimeMillis()</tt> is negative. 186 * @throws IllegalStateException if task was already scheduled or 187 * cancelled, timer was cancelled, or timer thread terminated. 188 * @throws NullPointerException if {@code task} is null 189 */ 190 public void schedule(TimerTask task, long delay) { 191 if (delay < 0) 192 throw new IllegalArgumentException("Negative delay."); 193 sched(task, System.currentTimeMillis()+delay, 0); 194 } 195 196 /** 197 * Schedules the specified task for execution at the specified time. If 198 * the time is in the past, the task is scheduled for immediate execution. 199 * 200 * @param task task to be scheduled. 201 * @param time time at which task is to be executed. 202 * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative. 203 * @throws IllegalStateException if task was already scheduled or 204 * cancelled, timer was cancelled, or timer thread terminated. 205 * @throws NullPointerException if {@code task} or {@code time} is null 206 */ 207 public void schedule(TimerTask task, Date time) { 208 sched(task, time.getTime(), 0); 209 } 210 211 /** 212 * Schedules the specified task for repeated <i>fixed-delay execution</i>, 213 * beginning after the specified delay. Subsequent executions take place 214 * at approximately regular intervals separated by the specified period. 215 * 216 * <p>In fixed-delay execution, each execution is scheduled relative to 217 * the actual execution time of the previous execution. If an execution 218 * is delayed for any reason (such as garbage collection or other 219 * background activity), subsequent executions will be delayed as well. 220 * In the long run, the frequency of execution will generally be slightly 221 * lower than the reciprocal of the specified period (assuming the system 222 * clock underlying <tt>Object.wait(long)</tt> is accurate). 223 * 224 * <p>Fixed-delay execution is appropriate for recurring activities 225 * that require "smoothness." In other words, it is appropriate for 226 * activities where it is more important to keep the frequency accurate 227 * in the short run than in the long run. This includes most animation 228 * tasks, such as blinking a cursor at regular intervals. It also includes 229 * tasks wherein regular activity is performed in response to human 230 * input, such as automatically repeating a character as long as a key 231 * is held down. 232 * 233 * @param task task to be scheduled. 234 * @param delay delay in milliseconds before task is to be executed. 235 * @param period time in milliseconds between successive task executions. 236 * @throws IllegalArgumentException if {@code delay < 0}, or 237 * {@code delay + System.currentTimeMillis() < 0}, or 238 * {@code period <= 0} 239 * @throws IllegalStateException if task was already scheduled or 240 * cancelled, timer was cancelled, or timer thread terminated. 241 * @throws NullPointerException if {@code task} is null 242 */ 243 public void schedule(TimerTask task, long delay, long period) { 244 if (delay < 0) 245 throw new IllegalArgumentException("Negative delay."); 246 if (period <= 0) 247 throw new IllegalArgumentException("Non-positive period."); 248 sched(task, System.currentTimeMillis()+delay, -period); 249 } 250 251 /** 252 * Schedules the specified task for repeated <i>fixed-delay execution</i>, 253 * beginning at the specified time. Subsequent executions take place at 254 * approximately regular intervals, separated by the specified period. 255 * 256 * <p>In fixed-delay execution, each execution is scheduled relative to 257 * the actual execution time of the previous execution. If an execution 258 * is delayed for any reason (such as garbage collection or other 259 * background activity), subsequent executions will be delayed as well. 260 * In the long run, the frequency of execution will generally be slightly 261 * lower than the reciprocal of the specified period (assuming the system 262 * clock underlying <tt>Object.wait(long)</tt> is accurate). As a 263 * consequence of the above, if the scheduled first time is in the past, 264 * it is scheduled for immediate execution. 265 * 266 * <p>Fixed-delay execution is appropriate for recurring activities 267 * that require "smoothness." In other words, it is appropriate for 268 * activities where it is more important to keep the frequency accurate 269 * in the short run than in the long run. This includes most animation 270 * tasks, such as blinking a cursor at regular intervals. It also includes 271 * tasks wherein regular activity is performed in response to human 272 * input, such as automatically repeating a character as long as a key 273 * is held down. 274 * 275 * @param task task to be scheduled. 276 * @param firstTime First time at which task is to be executed. 277 * @param period time in milliseconds between successive task executions. 278 * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or 279 * {@code period <= 0} 280 * @throws IllegalStateException if task was already scheduled or 281 * cancelled, timer was cancelled, or timer thread terminated. 282 * @throws NullPointerException if {@code task} or {@code firstTime} is null 283 */ 284 public void schedule(TimerTask task, Date firstTime, long period) { 285 if (period <= 0) 286 throw new IllegalArgumentException("Non-positive period."); 287 sched(task, firstTime.getTime(), -period); 288 } 289 290 /** 291 * Schedules the specified task for repeated <i>fixed-rate execution</i>, 292 * beginning after the specified delay. Subsequent executions take place 293 * at approximately regular intervals, separated by the specified period. 294 * 295 * <p>In fixed-rate execution, each execution is scheduled relative to the 296 * scheduled execution time of the initial execution. If an execution is 297 * delayed for any reason (such as garbage collection or other background 298 * activity), two or more executions will occur in rapid succession to 299 * "catch up." In the long run, the frequency of execution will be 300 * exactly the reciprocal of the specified period (assuming the system 301 * clock underlying <tt>Object.wait(long)</tt> is accurate). 302 * 303 * <p>Fixed-rate execution is appropriate for recurring activities that 304 * are sensitive to <i>absolute</i> time, such as ringing a chime every 305 * hour on the hour, or running scheduled maintenance every day at a 306 * particular time. It is also appropriate for recurring activities 307 * where the total time to perform a fixed number of executions is 308 * important, such as a countdown timer that ticks once every second for 309 * ten seconds. Finally, fixed-rate execution is appropriate for 310 * scheduling multiple repeating timer tasks that must remain synchronized 311 * with respect to one another. 312 * 313 * @param task task to be scheduled. 314 * @param delay delay in milliseconds before task is to be executed. 315 * @param period time in milliseconds between successive task executions. 316 * @throws IllegalArgumentException if {@code delay < 0}, or 317 * {@code delay + System.currentTimeMillis() < 0}, or 318 * {@code period <= 0} 319 * @throws IllegalStateException if task was already scheduled or 320 * cancelled, timer was cancelled, or timer thread terminated. 321 * @throws NullPointerException if {@code task} is null 322 */ 323 public void scheduleAtFixedRate(TimerTask task, long delay, long period) { 324 if (delay < 0) 325 throw new IllegalArgumentException("Negative delay."); 326 if (period <= 0) 327 throw new IllegalArgumentException("Non-positive period."); 328 sched(task, System.currentTimeMillis()+delay, period); 329 } 330 331 /** 332 * Schedules the specified task for repeated <i>fixed-rate execution</i>, 333 * beginning at the specified time. Subsequent executions take place at 334 * approximately regular intervals, separated by the specified period. 335 * 336 * <p>In fixed-rate execution, each execution is scheduled relative to the 337 * scheduled execution time of the initial execution. If an execution is 338 * delayed for any reason (such as garbage collection or other background 339 * activity), two or more executions will occur in rapid succession to 340 * "catch up." In the long run, the frequency of execution will be 341 * exactly the reciprocal of the specified period (assuming the system 342 * clock underlying <tt>Object.wait(long)</tt> is accurate). As a 343 * consequence of the above, if the scheduled first time is in the past, 344 * then any "missed" executions will be scheduled for immediate "catch up" 345 * execution. 346 * 347 * <p>Fixed-rate execution is appropriate for recurring activities that 348 * are sensitive to <i>absolute</i> time, such as ringing a chime every 349 * hour on the hour, or running scheduled maintenance every day at a 350 * particular time. It is also appropriate for recurring activities 351 * where the total time to perform a fixed number of executions is 352 * important, such as a countdown timer that ticks once every second for 353 * ten seconds. Finally, fixed-rate execution is appropriate for 354 * scheduling multiple repeating timer tasks that must remain synchronized 355 * with respect to one another. 356 * 357 * @param task task to be scheduled. 358 * @param firstTime First time at which task is to be executed. 359 * @param period time in milliseconds between successive task executions. 360 * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or 361 * {@code period <= 0} 362 * @throws IllegalStateException if task was already scheduled or 363 * cancelled, timer was cancelled, or timer thread terminated. 364 * @throws NullPointerException if {@code task} or {@code firstTime} is null 365 */ 366 public void scheduleAtFixedRate(TimerTask task, Date firstTime, 367 long period) { 368 if (period <= 0) 369 throw new IllegalArgumentException("Non-positive period."); 370 sched(task, firstTime.getTime(), period); 371 } 372 373 /** 374 * Schedule the specified timer task for execution at the specified 375 * time with the specified period, in milliseconds. If period is 376 * positive, the task is scheduled for repeated execution; if period is 377 * zero, the task is scheduled for one-time execution. Time is specified 378 * in Date.getTime() format. This method checks timer state, task state, 379 * and initial execution time, but not period. 380 * 381 * @throws IllegalArgumentException if <tt>time</tt> is negative. 382 * @throws IllegalStateException if task was already scheduled or 383 * cancelled, timer was cancelled, or timer thread terminated. 384 * @throws NullPointerException if {@code task} is null 385 */ 386 private void sched(TimerTask task, long time, long period) { 387 if (time < 0) 388 throw new IllegalArgumentException("Illegal execution time."); 389 390 // Constrain value of period sufficiently to prevent numeric 391 // overflow while still being effectively infinitely large. 392 if (Math.abs(period) > (Long.MAX_VALUE >> 1)) 393 period >>= 1; 394 395 synchronized(queue) { 396 if (!thread.newTasksMayBeScheduled) 397 throw new IllegalStateException("Timer already cancelled."); 398 399 synchronized(task.lock) { 400 if (task.state != TimerTask.VIRGIN) 401 throw new IllegalStateException( | 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 import java.util.Date; 28 import java.util.concurrent.atomic.AtomicInteger; 29 30 /** 31 * A facility for threads to schedule tasks for future execution in a 32 * background thread. Tasks may be scheduled for one-time execution, or for 33 * repeated execution at regular intervals. 34 * 35 * <p>Corresponding to each {@code Timer} object is a single background 36 * thread that is used to execute all of the timer's tasks, sequentially. 37 * Timer tasks should complete quickly. If a timer task takes excessive time 38 * to complete, it "hogs" the timer's task execution thread. This can, in 39 * turn, delay the execution of subsequent tasks, which may "bunch up" and 40 * execute in rapid succession when (and if) the offending task finally 41 * completes. 42 * 43 * <p>After the last live reference to a {@code Timer} object goes away 44 * <i>and</i> all outstanding tasks have completed execution, the timer's task 45 * execution thread terminates gracefully (and becomes subject to garbage 46 * collection). However, this can take arbitrarily long to occur. By 47 * default, the task execution thread does not run as a <i>daemon thread</i>, 48 * so it is capable of keeping an application from terminating. If a caller 49 * wants to terminate a timer's task execution thread rapidly, the caller 50 * should invoke the timer's {@code cancel} method. 51 * 52 * <p>If the timer's task execution thread terminates unexpectedly, for 53 * example, because its {@code stop} method is invoked, any further 54 * attempt to schedule a task on the timer will result in an 55 * {@code IllegalStateException}, as if the timer's {@code cancel} 56 * method had been invoked. 57 * 58 * <p>This class is thread-safe: multiple threads can share a single 59 * {@code Timer} object without the need for external synchronization. 60 * 61 * <p>This class does <i>not</i> offer real-time guarantees: it schedules 62 * tasks using the {@code Object.wait(long)} method. 63 * 64 * <p>Java 5.0 introduced the {@code java.util.concurrent} package and 65 * one of the concurrency utilities therein is the {@link 66 * java.util.concurrent.ScheduledThreadPoolExecutor 67 * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly 68 * executing tasks at a given rate or delay. It is effectively a more 69 * versatile replacement for the {@code Timer}/{@code TimerTask} 70 * combination, as it allows multiple service threads, accepts various 71 * time units, and doesn't require subclassing {@code TimerTask} (just 72 * implement {@code Runnable}). Configuring {@code 73 * ScheduledThreadPoolExecutor} with one thread makes it equivalent to 74 * {@code Timer}. 75 * 76 * <p>Implementation note: This class scales to large numbers of concurrently 77 * scheduled tasks (thousands should present no problem). Internally, 78 * it uses a binary heap to represent its task queue, so the cost to schedule 79 * a task is O(log n), where n is the number of concurrently scheduled tasks. 80 * 81 * <p>Implementation note: All constructors start a timer thread. 82 * 164 * Creates a new timer whose associated thread has the specified name, 165 * and may be specified to 166 * {@linkplain Thread#setDaemon run as a daemon}. 167 * 168 * @param name the name of the associated thread 169 * @param isDaemon true if the associated thread should run as a daemon 170 * @throws NullPointerException if {@code name} is null 171 * @since 1.5 172 */ 173 public Timer(String name, boolean isDaemon) { 174 thread.setName(name); 175 thread.setDaemon(isDaemon); 176 thread.start(); 177 } 178 179 /** 180 * Schedules the specified task for execution after the specified delay. 181 * 182 * @param task task to be scheduled. 183 * @param delay delay in milliseconds before task is to be executed. 184 * @throws IllegalArgumentException if {@code delay} is negative, or 185 * {@code delay + System.currentTimeMillis()} is negative. 186 * @throws IllegalStateException if task was already scheduled or 187 * cancelled, timer was cancelled, or timer thread terminated. 188 * @throws NullPointerException if {@code task} is null 189 */ 190 public void schedule(TimerTask task, long delay) { 191 if (delay < 0) 192 throw new IllegalArgumentException("Negative delay."); 193 sched(task, System.currentTimeMillis()+delay, 0); 194 } 195 196 /** 197 * Schedules the specified task for execution at the specified time. If 198 * the time is in the past, the task is scheduled for immediate execution. 199 * 200 * @param task task to be scheduled. 201 * @param time time at which task is to be executed. 202 * @throws IllegalArgumentException if {@code time.getTime()} is negative. 203 * @throws IllegalStateException if task was already scheduled or 204 * cancelled, timer was cancelled, or timer thread terminated. 205 * @throws NullPointerException if {@code task} or {@code time} is null 206 */ 207 public void schedule(TimerTask task, Date time) { 208 sched(task, time.getTime(), 0); 209 } 210 211 /** 212 * Schedules the specified task for repeated <i>fixed-delay execution</i>, 213 * beginning after the specified delay. Subsequent executions take place 214 * at approximately regular intervals separated by the specified period. 215 * 216 * <p>In fixed-delay execution, each execution is scheduled relative to 217 * the actual execution time of the previous execution. If an execution 218 * is delayed for any reason (such as garbage collection or other 219 * background activity), subsequent executions will be delayed as well. 220 * In the long run, the frequency of execution will generally be slightly 221 * lower than the reciprocal of the specified period (assuming the system 222 * clock underlying {@code Object.wait(long)} is accurate). 223 * 224 * <p>Fixed-delay execution is appropriate for recurring activities 225 * that require "smoothness." In other words, it is appropriate for 226 * activities where it is more important to keep the frequency accurate 227 * in the short run than in the long run. This includes most animation 228 * tasks, such as blinking a cursor at regular intervals. It also includes 229 * tasks wherein regular activity is performed in response to human 230 * input, such as automatically repeating a character as long as a key 231 * is held down. 232 * 233 * @param task task to be scheduled. 234 * @param delay delay in milliseconds before task is to be executed. 235 * @param period time in milliseconds between successive task executions. 236 * @throws IllegalArgumentException if {@code delay < 0}, or 237 * {@code delay + System.currentTimeMillis() < 0}, or 238 * {@code period <= 0} 239 * @throws IllegalStateException if task was already scheduled or 240 * cancelled, timer was cancelled, or timer thread terminated. 241 * @throws NullPointerException if {@code task} is null 242 */ 243 public void schedule(TimerTask task, long delay, long period) { 244 if (delay < 0) 245 throw new IllegalArgumentException("Negative delay."); 246 if (period <= 0) 247 throw new IllegalArgumentException("Non-positive period."); 248 sched(task, System.currentTimeMillis()+delay, -period); 249 } 250 251 /** 252 * Schedules the specified task for repeated <i>fixed-delay execution</i>, 253 * beginning at the specified time. Subsequent executions take place at 254 * approximately regular intervals, separated by the specified period. 255 * 256 * <p>In fixed-delay execution, each execution is scheduled relative to 257 * the actual execution time of the previous execution. If an execution 258 * is delayed for any reason (such as garbage collection or other 259 * background activity), subsequent executions will be delayed as well. 260 * In the long run, the frequency of execution will generally be slightly 261 * lower than the reciprocal of the specified period (assuming the system 262 * clock underlying {@code Object.wait(long)} is accurate). As a 263 * consequence of the above, if the scheduled first time is in the past, 264 * it is scheduled for immediate execution. 265 * 266 * <p>Fixed-delay execution is appropriate for recurring activities 267 * that require "smoothness." In other words, it is appropriate for 268 * activities where it is more important to keep the frequency accurate 269 * in the short run than in the long run. This includes most animation 270 * tasks, such as blinking a cursor at regular intervals. It also includes 271 * tasks wherein regular activity is performed in response to human 272 * input, such as automatically repeating a character as long as a key 273 * is held down. 274 * 275 * @param task task to be scheduled. 276 * @param firstTime First time at which task is to be executed. 277 * @param period time in milliseconds between successive task executions. 278 * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or 279 * {@code period <= 0} 280 * @throws IllegalStateException if task was already scheduled or 281 * cancelled, timer was cancelled, or timer thread terminated. 282 * @throws NullPointerException if {@code task} or {@code firstTime} is null 283 */ 284 public void schedule(TimerTask task, Date firstTime, long period) { 285 if (period <= 0) 286 throw new IllegalArgumentException("Non-positive period."); 287 sched(task, firstTime.getTime(), -period); 288 } 289 290 /** 291 * Schedules the specified task for repeated <i>fixed-rate execution</i>, 292 * beginning after the specified delay. Subsequent executions take place 293 * at approximately regular intervals, separated by the specified period. 294 * 295 * <p>In fixed-rate execution, each execution is scheduled relative to the 296 * scheduled execution time of the initial execution. If an execution is 297 * delayed for any reason (such as garbage collection or other background 298 * activity), two or more executions will occur in rapid succession to 299 * "catch up." In the long run, the frequency of execution will be 300 * exactly the reciprocal of the specified period (assuming the system 301 * clock underlying {@code Object.wait(long)} is accurate). 302 * 303 * <p>Fixed-rate execution is appropriate for recurring activities that 304 * are sensitive to <i>absolute</i> time, such as ringing a chime every 305 * hour on the hour, or running scheduled maintenance every day at a 306 * particular time. It is also appropriate for recurring activities 307 * where the total time to perform a fixed number of executions is 308 * important, such as a countdown timer that ticks once every second for 309 * ten seconds. Finally, fixed-rate execution is appropriate for 310 * scheduling multiple repeating timer tasks that must remain synchronized 311 * with respect to one another. 312 * 313 * @param task task to be scheduled. 314 * @param delay delay in milliseconds before task is to be executed. 315 * @param period time in milliseconds between successive task executions. 316 * @throws IllegalArgumentException if {@code delay < 0}, or 317 * {@code delay + System.currentTimeMillis() < 0}, or 318 * {@code period <= 0} 319 * @throws IllegalStateException if task was already scheduled or 320 * cancelled, timer was cancelled, or timer thread terminated. 321 * @throws NullPointerException if {@code task} is null 322 */ 323 public void scheduleAtFixedRate(TimerTask task, long delay, long period) { 324 if (delay < 0) 325 throw new IllegalArgumentException("Negative delay."); 326 if (period <= 0) 327 throw new IllegalArgumentException("Non-positive period."); 328 sched(task, System.currentTimeMillis()+delay, period); 329 } 330 331 /** 332 * Schedules the specified task for repeated <i>fixed-rate execution</i>, 333 * beginning at the specified time. Subsequent executions take place at 334 * approximately regular intervals, separated by the specified period. 335 * 336 * <p>In fixed-rate execution, each execution is scheduled relative to the 337 * scheduled execution time of the initial execution. If an execution is 338 * delayed for any reason (such as garbage collection or other background 339 * activity), two or more executions will occur in rapid succession to 340 * "catch up." In the long run, the frequency of execution will be 341 * exactly the reciprocal of the specified period (assuming the system 342 * clock underlying {@code Object.wait(long)} is accurate). As a 343 * consequence of the above, if the scheduled first time is in the past, 344 * then any "missed" executions will be scheduled for immediate "catch up" 345 * execution. 346 * 347 * <p>Fixed-rate execution is appropriate for recurring activities that 348 * are sensitive to <i>absolute</i> time, such as ringing a chime every 349 * hour on the hour, or running scheduled maintenance every day at a 350 * particular time. It is also appropriate for recurring activities 351 * where the total time to perform a fixed number of executions is 352 * important, such as a countdown timer that ticks once every second for 353 * ten seconds. Finally, fixed-rate execution is appropriate for 354 * scheduling multiple repeating timer tasks that must remain synchronized 355 * with respect to one another. 356 * 357 * @param task task to be scheduled. 358 * @param firstTime First time at which task is to be executed. 359 * @param period time in milliseconds between successive task executions. 360 * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or 361 * {@code period <= 0} 362 * @throws IllegalStateException if task was already scheduled or 363 * cancelled, timer was cancelled, or timer thread terminated. 364 * @throws NullPointerException if {@code task} or {@code firstTime} is null 365 */ 366 public void scheduleAtFixedRate(TimerTask task, Date firstTime, 367 long period) { 368 if (period <= 0) 369 throw new IllegalArgumentException("Non-positive period."); 370 sched(task, firstTime.getTime(), period); 371 } 372 373 /** 374 * Schedule the specified timer task for execution at the specified 375 * time with the specified period, in milliseconds. If period is 376 * positive, the task is scheduled for repeated execution; if period is 377 * zero, the task is scheduled for one-time execution. Time is specified 378 * in Date.getTime() format. This method checks timer state, task state, 379 * and initial execution time, but not period. 380 * 381 * @throws IllegalArgumentException if {@code time} is negative. 382 * @throws IllegalStateException if task was already scheduled or 383 * cancelled, timer was cancelled, or timer thread terminated. 384 * @throws NullPointerException if {@code task} is null 385 */ 386 private void sched(TimerTask task, long time, long period) { 387 if (time < 0) 388 throw new IllegalArgumentException("Illegal execution time."); 389 390 // Constrain value of period sufficiently to prevent numeric 391 // overflow while still being effectively infinitely large. 392 if (Math.abs(period) > (Long.MAX_VALUE >> 1)) 393 period >>= 1; 394 395 synchronized(queue) { 396 if (!thread.newTasksMayBeScheduled) 397 throw new IllegalStateException("Timer already cancelled."); 398 399 synchronized(task.lock) { 400 if (task.state != TimerTask.VIRGIN) 401 throw new IllegalStateException( |