/*
Nord Modular Midi Protocol 3.03 Library
Copyright (C) 2003-2006 Marcus Andersson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package net.sf.nmedit.jnmprotocol.utils;
import net.sf.nmedit.jnmprotocol.utils.ThreadExecutionPolicy;
public class StoppableThread implements Runnable
{
// controls the execution of the thread loop
private ThreadExecutionPolicy executionPolicy;
// will be called inside the thread loop
private Runnable runnable;
// The thread which executes this runnable.
// The variable is uses to determine if
// run() is executed in the correct thread
private volatile Thread workerThread;
// indicates that the thread loop is exited
private volatile boolean stopped = false;
public StoppableThread(ThreadExecutionPolicy executionPolicy, Runnable runnable)
{
this.executionPolicy = executionPolicy;
this.runnable = runnable;
}
/**
* Starts a new worker thread in which this thread loop is executed.
* If isStarted() is already true nothing will happen.
*/
public synchronized void start()
{
if (isStarted())
return ;
stopped = false;
workerThread = new Thread(this);
workerThread.setDaemon(false);
workerThread.start();
}
/**
* Stops the current worker thread.
*/
public synchronized void stop()
{
workerThread = null;
// this is necessary if the thread is sleeping,
// otherwise it might 'never' wake up
executionPolicy.interruptDelay();
}
/**
* Returns true if start() was called but the thread is not finished yet.
*/
public boolean isStarted()
{
return workerThread != null;
}
/**
* Returns true if the thread loop was executed and is already finished.
*/
public boolean isStopped()
{
return stopped;
}
public void run()
{
// the thread in which run() is executed
Thread thisThread = Thread.currentThread();
try
{
// loop runs as long the following conditions are true:
// 1. the workerThread and this thread are identical
// 2. the executionPolicy object does not indicate that the loop can exit
while (workerThread == thisThread && (!executionPolicy.exitRequested()))
{
// checks if the runnable should be executed
if (executionPolicy.executionRequested())
{
runnable.run();
}
// sleep for a unspecified amount of time
try
{
executionPolicy.delay();
}
catch (InterruptedException e)
{
// no op
}
}
}
finally
{
// set the stopped flag
stopped = true;
// erase the workerThread variable
workerThread = null;
}
}
}