📄 task.java
字号:
// Task - a periodic action
//
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package Acme;
import java.util.*;
/// A periodic action.
// <P>
// A Task represents a bit of code that you want to run repeatedly at
// equally-timed intervals. Doing the timing yourself via sleeps is
// either inaccurate, since it depends on how long the task takes to
// run, or else complicated. Well, this class does the timing accurately
// but hides the complexity from you.
// <P>
// Tasks use the Runnable interface, just like Threads. This means that
// just like with Threads, there are two different ways you can create
// a Task:
// <UL>
// <LI>
// You can have your class implement the Runnable interface and add
// a run() method:
// <BLOCKQUOTE><CODE><PRE>
// class Anim implements Runnable
// {
// public void run()
// {
// // do an animation frame
// }
// }
// </PRE></CODE></BLOCKQUOTE>
// To start this task you would use something like this:
// <BLOCKQUOTE><CODE><PRE>
// Anim a = new Anim();
// Acme.Task t = new Acme.Task( a, 1000 );
// </PRE></CODE></BLOCKQUOTE>
// Or if, as is likely, your class starts the task in its constructor:
// <BLOCKQUOTE><CODE><PRE>
// Acme.Task t = new Acme.Task( this, 1000 );
// </PRE></CODE></BLOCKQUOTE>
// <LI>
// The other way to create a Task is to make a subclass of Task and override
// the run() method:
// <BLOCKQUOTE><CODE><PRE>
// class AnimTask extends Acme.Task
// {
// public void run()
// {
// // do an animation frame
// }
// }
// </PRE></CODE></BLOCKQUOTE>
// Then you would start it like so:
// <BLOCKQUOTE><CODE><PRE>
// Acme.Task t = new AnimTask( 1000 );
// </PRE></CODE></BLOCKQUOTE>
// </UL>
// <P>
// <A HREF="/resources/classes/Acme/Task.java">Fetch the software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
public class Task implements Runnable
{
/*private*/ protected Runnable runnable;
/*private*/ protected long msPeriod;
/*private*/ protected TaskRunner runner;
/*private*/ protected long nextRun;
/// Constructor for subclasses that override run().
public Task( long msPeriod )
{
this( null, msPeriod );
}
/// Constructor with a Runnable specified.
public Task( Runnable runnable, long msPeriod )
{
this.runnable = runnable;
this.msPeriod = msPeriod;
runner = new TaskRunner( this );
TaskTimer.add( this );
}
/// The body of the Task.
// You must either override this method by subclassing class Task,
// or you must create the Task with a Runnable target.
public void run()
{
if ( runnable == null )
throw new RuntimeException(); // didn't override
runnable.run();
}
/// Stops a Task from running in the future.
public synchronized void deschedule()
{
TaskTimer.deschedule( this );
}
}
// TaskRunner - thread for running a task
//
// There's one of these for each Task. However, we can't put these methods
// into the Task class itself because the run() method has to be a loop here.
class TaskRunner extends Thread
{
private Task task;
/*private*/ protected boolean done;
public TaskRunner( Task task )
{
this.task = task;
done = false;
this.start();
}
public synchronized void run()
{
while ( true )
{
try
{
wait();
}
catch ( InterruptedException e ) { }
if ( done )
break;
task.run();
}
}
public synchronized void notifier()
{
notify();
}
}
// TaskTimer - trigger TaskRunners at the right moment
//
// Only one of these gets created, and it handles the timing of all the
// Tasks.
class TaskTimer extends Thread
{
private static boolean done = true;
private static Vector tasks = null;
private static TaskTimer timer = null;
public static synchronized void add( Task task )
{
task.nextRun = System.currentTimeMillis() + task.msPeriod;
if ( tasks == null )
tasks = new Vector();
tasks.addElement( task );
sortTasks( tasks );
if ( timer == null )
{
done = false;
timer = new TaskTimer();
}
}
public static synchronized void deschedule( Task task )
{
task.runner.done = true;
task.runner.notifier();
tasks.removeElement( task );
if ( tasks.size() == 0 )
{
done = true;
tasks = null;
timer.notifier();
timer = null;
}
}
public TaskTimer()
{
this.setPriority( Thread.MAX_PRIORITY );
this.start();
}
public synchronized void run()
{
while ( true )
{
if ( done )
break;
// The tasks are kept sorted by nextRun, so the next runnable
// task is the first one in the list.
Task nextTask = (Task) tasks.elementAt( 0 );
long nextRun = nextTask.nextRun;
// Sleep until it's time to run it.
try
{
wait( nextRun - System.currentTimeMillis() );
}
catch ( InterruptedException e ) { }
if ( done )
break;
// Run all tasks that should be run.
long now = System.currentTimeMillis();
for ( int i = 0; i < tasks.size(); ++i )
{
Task task = (Task) tasks.elementAt( i );
if ( task.nextRun > now )
break;
task.runner.notifier();
task.nextRun += task.msPeriod;
}
// And re-sort, since the nextRuns have changed.
sortTasks( tasks );
}
}
/// Stupid bubble sort. Maybe someday Java will have a Sortable interface.
private static void sortTasks( Vector tasks )
{
for ( int i = 0; i < tasks.size() - i; ++i )
{
Task taski = (Task) tasks.elementAt( i );
for ( int j = i + 1; j < tasks.size(); ++j )
{
Task taskj = (Task) tasks.elementAt( j );
if ( taskj.nextRun < taski.nextRun )
{
tasks.setElementAt( taskj, i );
tasks.setElementAt( taski, j );
taski = taskj;
}
}
}
}
public synchronized void notifier()
{
notify();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -