I am making a simple button game with JavaFX and I need a thread to run so that I can check if an enemy or the player is alive or not. My problem is not starting and using the thread, but stopping it when the window is closed.
I made a sample class to demonstrate what I mean.
private Thread thread;
private boolean running;
private Stage window;
public void run() {
while (running) {
System.out.println("Hello");
}
stopThread();
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.start();
}
public synchronized void stopThread() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start(Stage stage) throws Exception {
window = new Stage();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(e -> {
e.consume();
close();
});
window.setScene(scene);
window.show();
}
public void close() {
window.close();
stopThread();
}
public static void main(String[] args) {
Things things = new Things();
things.startThread();
launch(args);
}
When I run it, "Hello" prints continuously, but when I try to close it, the thread keeps running and eclispe goes into debug mode saying:
Thread [JavaFX Application Thread] (Suspended (exception NullPointerException))
QuantumToolkit.runWithoutRenderLock(Supplier<T>) line: not available
GlassWindowEventHandler.handleWindowEvent(Window, long, int) line: not available
WinWindow(Window).handleWindowEvent(long, int) line: not available
WinWindow(Window).notifyClose() line: not available
WinApplication._runLoop(Runnable) line: not available [native method]
WinApplication.lambda$null$145(Runnable) line: not available
2091156596.run() line: not available
Thread.run() line: not available
I have looked around my code and cannot find anything that is null, though.
Assuming Things is the name of the class you showed, you're not stopping the correct thread.
When you call launch(args), the FX Toolkit creates an instance of the application class (which I'm assuming is Things), creates a Stage, and passes the Stage to the application instance's start(...) method (executing that method on the FX Application Thread).
So you create one instance, and start the thread on that instance. Then the FX toolkit creates a second instance, and it's on that instance that you are trying to stop the thread. So you are stopping a different thread to the one you started.
The fix for this is to remove the lines
Things things = new Things();
things.startThread();
from your main(...) method, and just to add
this.startThread();
to the beginning of your start(...) method.
Additionally, as #RyanJ points out, you are deadlocking as you have one thread waiting on a second thread to complete, and both are trying to execute the same synchronized method. Also, you should declare running as volatile, since it is accessed from multiple threads:
private volatile boolean running ;
So this works:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Things extends Application implements Runnable {
private Thread thread;
private volatile boolean running;
private Stage window;
#Override
public void run() {
while (running) {
System.out.println("Hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// stopThread();
running = false ;
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.start();
}
public synchronized void stopThread() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void start(Stage stage) throws Exception {
startThread();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(e -> {
e.consume();
close();
});
window.setScene(scene);
window.show();
}
public void close() {
window.close();
stopThread();
}
public static void main(String[] args) {
launch(args);
}
}
One last point: if this is the only window you have open, the JVM will exit when you close the window, as long as there are no non-daemon threads running. So you can just let the JVM kill your thread by making it a daemon thread. If this works for your real app, you could do any clean-up you needed by overriding the stop method:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Things extends Application implements Runnable {
private Thread thread;
private volatile boolean running;
private Stage window;
#Override
public void run() {
while (running) {
System.out.println("Hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// stopThread();
running = false ;
}
public synchronized void startThread() {
running = true;
thread = new Thread(this, "Monitor");
thread.setDaemon(true);
thread.start();
}
#Override
public void start(Stage stage) throws Exception {
startThread();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setScene(scene);
window.show();
}
public static void main(String[] args) {
launch(args);
}
}
You're probably hitting a livelock/deadlock situation.
In your run method, after the while loop terminates, you have your thread try to stop itself, and then attempt to wait for itself to die. That's a synchronized method, meaning only one thread can be running it at a time.
When you call it from your main method and try to stop the thread, it will try to join the thread and wait for it to die. Since this first call is already executing your stopThread method, when the while loop terminates in your run method, it will sit there and block, not causing the thread to die. Since the thread doesn't die, the first call to stopThread won't finish.
You could remove stopThread from your run method and it should behave better, though from what you posted here, it looks like a better design might be in order. I'd be curious if my suggestion works.
Upon further inspection, you also have a problem with static/non-static data within your threads.
I'm assuming your Things class implements Runnable, thus when you pass it to the Thread constructor and start it, it gets its own copy of the stack, and it's own local variables. When you call stopThread in your close method, you're not setting the proper running variable (it's not the one the thread running sees). If you make that field static and remove the thread.join... code, it behaves properly.
EDIT:
As a better design choice, it might be wiser to leverage the capability you get with Threads/Runnables and the way they are typically managed in an application (for more info, since you're using JFX, you should look at Services/Tasks)
Split up the thread implementation and the main class, and leverage the function of the thread itself to stop it.
Take this example, which is significantly cleaner, and works just as well:
public class Things implements Runnable {
private volatile boolean running; // this indicates it's running
public Things() {
running = true; // thread is running when it's created (though not really until "run" is called)
}
// called from start()
public void run() {
while (running) {
System.out.println("Hello");
}
}
// call this method to stop the thread, from outside on the object reference
public synchronized void stop() {
running = false;
}
}
In a separate Test/Application class, you can manipulate the Things reference to do what you want, without maintaining a reference to the actual thread.
public class Test extends Application {
private Stage window;
private static Things things;
public void start(Stage stage) throws Exception {
window = new Stage();
window = stage;
Pane layout = new Pane();
Scene scene = new Scene(layout);
window.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent windowEvent) {
close();
}
});
window.setScene(scene);
window.show();
}
// on close
public void close() {
window.close();
things.stop(); // stop the things object directly
}
public static void main(String[] args) {
things = new Things(); // create new runnable
Thread t = new Thread(things,"Monitor"); // create thread
t.start(); // start thread
launch(args); // launch app
}
}
Related
I'm writing a program that listens to clipboard changes and print that changes to stdout (it's just a test for a bigger program). The problem is: when the main thread finishes, the JVM exits and no events arrive to the listener. How can I do to keep JVM running while listening the clipboard?
My code looks like this:
public class Test {
public static void main(String[] args) {
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
cb.addFlavorListener(new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
System.out.println(e);
}
});
}
}
Thanks!
How can I do to keep JVM running while listening the clipboard?
I can't see how you would tell the program to stop listening to the clipboard in a proper way.
What I would do is just print some kind of message using standard out indicating a key to exit the program and then calling a scanner or similiar for checking the input. This way you achieve 2 important points:
The thread doesn't die inmediately as the scanner does the "wait" part I think you are looking for.
Users get control over the thread's lifecycle, so they can terminate it whenever they want in a proper way
I would just let the main-Thread sleep:
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
public class Test {
public static void main(String[] args) throws InterruptedException {
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
cb.addFlavorListener(new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
System.out.println(e);
}
});
// sleep forever
Object o = new Object();
synchronized (o) {
o.wait();
}
}
}
It is important to keep at least one (non-deamon) thread alive, to keep your application running. An alive thread could be:
The main thread, put to sleep
A new thread, put to sleep
Any awt/swing application thread, that will usualy stay alive, as long as there is at least one element undisposed
Any other thread, listening to any interface (waiting for System.in, HTTP-Request, or just anything)
Concerning the sleep mechanism, here are my three different techiques:
Never do this, it will keep your CPU busy:
for(;;);
This code's intention is clearly visible:
for(;;) Thread.sleep(Long.MAX_VALUE);
More elegant:
Object o = new Object();
synchronized (o) {o.wait();}
See How do you hang a thread in Java in one line? for a discussion about sleeping.
Try this:
public static void listen() throws InterruptedException {
Thread t = new Thread (new Runnable(){
#Override
public void run() {
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable contents = cb.getContents(null);
cb.addFlavorListener(new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
try {
System.out.println("Got Data:"+(String)contents.getTransferData(DataFlavor.stringFlavor));
} catch (UnsupportedFlavorException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
}
});
t.setDaemon(true);
t.start();
while (true)
Thread.sleep(Long.MAX_VALUE);
}
I am facing one problem in my JavaFx application.
Preface: I don't want to be specific to my application only but want to be generalized so that people like me will get an idea on similar situation.
Background: Implementing a Javafx application using fxml file and multi-threading concept.
Summary: I tried make an application which basically uses multi threading to do some task, and once multi- threading is completed, it will sequentially move to another task. While doing the multi-threading the Main GUI freezes.
What I did,
//This is Main class
Parent Root -> defined on top
public Parent createContent(){
try{
root = FXMLLoader.load(getClass().getResource("Layout.fxml"));
}catch { .....}
}
public void start(){
stage.setScene(new Scene(createContent()));
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
Thread.sleep(1000);
return null ;
}
};
task.setOnSucceeded(event->{
stage.show();
});
new Thread(task).run();
}
public static void main(String[] args) {
launch(args);
}
// This is inside the controller on button click event
#FXML
private void start(ActionEvent event) { <---- This one is button click event
Thread t1 = new Thread(new Mul());
t1.start();
Thread t2 = new Thread (new Mul());
t2.start();
}
// Finally
public class Mul implements Runnable {
public void type() {
for (int a = 0; a < 200000; a++) {
System.out.println( Thread.currentThread().getName()+ " says " + a);
}
}
#Override
public void run() {
type();
}
}
Now, here is the outcome.
If I just start the threads from the controller then My main application does not freezes while the thread are running in background. However, since the application runs in a sequence, i.e the next step only works when the threads complete their work
I can use t1.join() and t2.join() , but doing so will freezes my main application(Main application here is the main GUI) and I cannot proceed with it until the threads are completed.
What could be the optimal solution, so that I can use multi threading without blocking the main application or What am I doing wrong here? (info, I came to this solution by following up different suggestions from Stack overflow and google)
Why not do
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
Mul m1 = new Mul();
m1.run();
Mul m2 = new Mul();
m2.run();
return null ;
}
};
new Thread(task).start();
If you really want to "chain" different tasks, call one from the other's onSucceeded handler:
Task<Void> task1 = new Task<Void>() {
#Override
public Void call() {
new Mul().run();
return null ;
}
};
Task <Void> task2 = new Task<Void>() {
#Override
public Void call() {
new Mul().run();
return null ;
}
};
task1.setOnSucceeded(e -> new Thread(task2).start());
new Thread(task1).start();
Obviously this is cleaner if you make Mul a Task subclass instead of a Runnable, and it's better to use an Executor with daemon threads, etc, but this should give you the idea.
During my Unit tests, I'd like to plot some figures using Java FX. Now the problem is that as soon as the Unit test are done, the JVM and thus Java FX shut down and I am not able to inspect the generated plots (unlike in the case where the "test" is just started from the main method). So my question is, is there a way to stop JUnit from exiting before particular threads are finished, i.e. to replicate the behaviour as the test is started from the main method directly? And yes, I am aware that plotting is most likely not really something which should be done during a unit test in general.
At the moment I am doing something like this:
//#ContextConfiguration(classes = {DummyConfig.class })
//#RunWith(SpringJUnit4ClassRunner.class)
public class MainViewTest {
private boolean fromMain = false;
// starting the "test" from main does not require explicit waiting for
// for the JavaFX thread to finish .. I'd like to replicate this
// behaviour in JUnit (by configuring JUnit, not my test or application code)
public static void main(String [] args){
new MainViewTest(true).test();
}
public MainViewTest(){}
private MainViewTest(boolean fromMain){
this.fromMain = fromMain;
}
#Test
public void test() {
//do some tests....
//plot some results...
PlotStage.plotStage(new QPMApplication() {
#Override
public Stage createStage() {
Stage stage = new Stage();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 300);
stage.setTitle("Stage");
stage.setScene(scene);
stage.setOnCloseRequest(new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent event) {
Platform.exit();
}
});
return stage;
}
});
System.out.println("Stage started");
// how to get rid of this block (or using a countdownlatch) but
// still waiting for the threads to finish?
Set<Thread> threads = Thread.getAllStackTraces().keySet();
if (!fromMain) {
System.out.println("checking threads...");
for (Thread thread : threads) {
if (thread.getName().contains("JavaFX")) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
The issue is here that I want to get rid of this nasty block to wait until all the JavaFX platform is explicitly exited.
I appreciate the answer regarding using a countdown latch instead of joining the Java FX thread explicitly. However this still requires me to explictly stop the current thread. However, I would rather like to "tell" JUnit somehow to wait for the JavaFX thread to finish.
So basically what I am looking for is a way to tell JUnit to wait for particular threads without any blocking code inside my test methods.
Appendix: Necessary classes for a minimal running example
public class PlotStage {
public static boolean toolkitInialized = false;
public static void plotStage(QPMApplication stageCreator) {
if (!toolkitInialized) {
Thread appThread = new Thread(new Runnable() {
#Override
public void run() {
Application.launch(InitApp.class);
}
});
appThread.start();
}
while (!toolkitInialized) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform.runLater(new Runnable() {
#Override
public void run() {
Stage stage = stageCreator.createStage();
stage.show();
}
});
}
public static class InitApp extends Application {
#Override
public void start(final Stage primaryStage) {
toolkitInialized = true;
}
}
}
public interface QPMApplication {
public abstract Stage createStage();
}
Use a CountDownLatch for that.
Initialize with 1.
When the Stage is closed, invoke countDown().
In the JUnit Test, call await() to wait for the Stage to be closed.
Example:
CountDownLatch cdl = new CountDownLatch(1);
// TODO show the stage and do not forget to add cdl.countDown() to your
// stage.setOnCloseRequest
cdl.await();
Alternative #1:
Use the JavaFX Junit Rule to perform all actions directly on the FX application Thread.
Alternative #2:
Use TestFX, for what I read from your updated description, it fits best.
I have a bunch of threads running concurrently. Sometimes a thread needs to notify other threads to wait for it to finish a job and signal them again to resume. Since I'm somehow new to Java's synchronization, I wonder what is the right way to do such thing. My code is something like this:
private void Concurrent() {
if (shouldRun()) {
// notify threads to pause and wait for them
DoJob();
// resume threads
}
// Normal job...
}
Update:
Note that the code I wrote is inside a class which will be executed by each thread. I don't have access to those threads or how they are running. I'm just inside threads.
Update 2:
My code is from a crawler class. The crawler class (crawler4j) knows how to handle concurrency. The only thing I need is to pause other crawlers before running a function and resume them afterwards. This code is the basics of my crawler:
public class TestCrawler extends WebCrawler {
private SingleThread()
{
//When this function is running, no other crawler should do anything
}
#Override
public void visit(Page page) {
if(SomeCriteria())
{
//make all other crawlers stop until I finish
SingleThread();
//let them resume
}
//Normal Stuff
}
}
Here is a short example on how to achieve this with the cool java concurrency stuff:
snip old code doesn't matter anymore with the Pause class.
EDIT:
Here is the new Test class:
package de.hotware.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
private Pause mPause;
public Test() {
this.mPause = new Pause();
}
public void concurrent() throws InterruptedException {
while(true) {
this.mPause.probe();
System.out.println("concurrent");
Thread.sleep(100);
}
}
public void crucial() throws InterruptedException {
int i = 0;
while (true) {
if (i++ % 2 == 0) {
this.mPause.pause(true);
System.out.println("crucial: exclusive execution");
this.mPause.pause(false);
} else {
System.out.println("crucial: normal execution");
Thread.sleep(1000);
}
}
}
public static void main(String[] args) {
final Test test = new Test();
Runnable run = new Runnable() {
#Override
public void run() {
try {
test.concurrent();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Runnable cruc = new Runnable() {
#Override
public void run() {
try {
test.crucial();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
ExecutorService serv = Executors.newCachedThreadPool();
serv.execute(run);
serv.execute(run);
serv.execute(cruc);
}
}
And the utility Pause class:
package de.hotware.test;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Utility class to pause and unpause threads
* with Java Concurrency
* #author Martin Braun
*/
public class Pause {
private Lock mLock;
private Condition mCondition;
private AtomicBoolean mAwait;
public Pause() {
this.mLock = new ReentrantLock();
this.mCondition = this.mLock.newCondition();
this.mAwait = new AtomicBoolean(false);
}
/**
* waits until the threads until this.mAwait is set to true
* #throws InterruptedException
*/
public void probe() throws InterruptedException {
while(this.mAwait.get()) {
this.mLock.lock();
try {
this.mCondition.await();
} finally {
this.mLock.unlock();
}
}
}
/**
* pauses or unpauses
*/
public void pause(boolean pValue) {
if(!pValue){
this.mLock.lock();
try {
this.mCondition.signalAll();
} finally {
this.mLock.unlock();
}
}
this.mAwait.set(pValue);
}
}
The basic usage is to call probe() before each run. This will block if it is paused until pause(false) is called.
Your class would look like this:
public class TestCrawler extends WebCrawler {
private Pause mPause;
public TestCrawler(Pause pPause) {
this.mPause = pPause;
}
private SingleThread()
{
//When this function is running, no other crawler should do anything
}
#Override
public void visit(Page page) {
if(SomeCriteria())
{
//only enter the crucial part once if it has to be exclusive
this.mPause.probe();
//make all other crawlers stop until I finish
this.mPause.pause(true);
SingleThread();
//let them resume
this.mPause.pause(false);
}
this.mPause.probe();
//Normal Stuff
}
}
public class StockMonitor extends Thread {
private boolean suspend = false;
private volatile Thread thread;
public StockMonitor() {
thread = this;
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
private synchronized void _wait() throws InterruptedException {
while (suspend) {
wait();
}
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
public synchronized void _resume() {
suspend = false;
notify();
}
// Use name with underscore, in order to avoid naming crashing with
// Thread's.
public synchronized void _suspend() {
suspend = true;
}
public void _stop() {
thread = null;
// Wake up from sleep.
interrupt();
}
#Override
public void run() {
final Thread thisThread = Thread.currentThread();
while (thisThread == thread) {
_wait();
// Do whatever you want right here.
}
}
}
Calling _resume and _suspend will enable you to resume and pause the Thread. _stop will let you stop the thread gracefully. Note that, once you stop the Thread, there is no way to resume it again. The Thread is no longer usable.
The code is being picked from a real world open source project : http://jstock.hg.sourceforge.net/hgweb/jstock/jstock/file/b17c0fbfe37c/src/org/yccheok/jstock/engine/RealTimeStockMonitor.java#l247
You can use wait() and notify()
thread waiting:
// define mutex as field
Object mutex = new Object();
// later:
synchronized(mutex) {
wait();
}
notify the thread to continue
synchronized (mutex) {
notify();
}
Is it possible to rewrite this code for better working with processor?
I have a class, which does some tasks with fixed periodicy in a separate thread. Sometimes this process can be paused and resumed. Currently I am using a flag for pausing, it works fine, but loop in this way still loads processor when process is paused. Is it possible to fix this?
private boolean mIsCanceled = false;
private boolean mIsPaused = true; // TODO more efficient for processor way of pausing is required
private final Thread mTimerThread = new Thread(new Runnable() {
#Override
public void run() {
while(!mIsCanceled){
try {
Thread.sleep(UPDATE_PERIOD);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!mIsPaused){
doStep();
}
}
}
});
public MyClass(){
mTimerThread.start();
}
private void pause(){
mIsPaused = true;
}
private void resume(){
mIsPaused = false;
}
private void doStep(){
// Some code
}
Please just provide alternative implementation of my code.
P.S. The environment is Android OS 2.2+
The tools available are:
wait/notify - we are all trying to get away from this archaic system.
Semaphores - once your thread has grabbed it you hold it until release so grabbing it again does not block. This means you cannot pause from within your own thread.
CyclicBarrier - Must be created anew each time it is used.
ReadWriteLock - My favorite. You can have as many threads pausing you as you like and you will only resume when all of them have called resume. You can even pause yourself if you wish.
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* PauseableThread is a Thread with pause/resume and cancel methods.
*
* The meat of the process must implement `step`.
*
* You can either extend this and implement `step` or use the factory.
*
* Note that I cannot extend Thread because my resume will clash with Thread's deprecated one.
*
* Usage: Either write a `Stepper` and run it in a `PausableThread` or extend `PausableThread` and call `blockIfPaused()` at appropriate points.
*/
public abstract class PauseableThread implements Runnable {
// The lock.
// We'll hold a read lock on it to pause the thread.
// The thread will momentarily grab a write lock on it to pause.
// This way you can have multiple pausers using normal locks.
private final ReadWriteLock pause = new ReentrantReadWriteLock();
// Flag to cancel the wholeprocess.
private volatile boolean cancelled = false;
// The exception that caused it to finish.
private Exception thrown = null;
#Override
// The core run mechanism.
public void run() {
try {
while (!cancelled) {
// Block here if we're paused.
blockIfPaused();
// Do my work.
step();
}
} catch (Exception ex) {
// Just fall out when exception is thrown.
thrown = ex;
}
}
// Block if pause has been called without a matching resume.
private void blockIfPaused() throws InterruptedException {
try {
// Grab a write lock. Will block if a read lock has been taken.
pause.writeLock().lockInterruptibly();
} finally {
// Release the lock immediately to avoid blocking when pause is called.
pause.writeLock().unlock();
}
}
// Pause the work. NB: MUST be balanced by a resume.
public void pause() {
// We can wait for a lock here.
pause.readLock().lock();
}
// Resume the work. NB: MUST be balanced by a pause.
public void resume() {
// Release the lock.
pause.readLock().unlock();
}
// Stop.
public void cancel() {
// Stop everything.
cancelled = true;
}
// start - like a thread.
public void start() {
// Wrap it in a thread.
new Thread(this).start();
}
// Get the exceptuion that was thrown to stop the thread or null if the thread was cancelled.
public Exception getThrown() {
return thrown;
}
// Create this method to do stuff.
// Calls to this method will stop when pause is called.
// Any thrown exception stops the whole process.
public abstract void step() throws Exception;
// Factory to wrap a Stepper in a PauseableThread
public static PauseableThread make(Stepper stepper) {
StepperThread pauseableStepper = new StepperThread(stepper);
// That's the thread they can pause/resume.
return pauseableStepper;
}
// One of these must be used.
public interface Stepper {
// A Stepper has a step method.
// Any exception thrown causes the enclosing thread to stop.
public void step() throws Exception;
}
// Holder for a Stepper.
private static class StepperThread extends PauseableThread {
private final Stepper stepper;
StepperThread(Stepper stepper) {
this.stepper = stepper;
}
#Override
public void step() throws Exception {
stepper.step();
}
}
// My test counter.
static int n = 0;
// Test/demo.
public static void main(String[] args) throws InterruptedException {
try {
// Simple stepper that just increments n.
Stepper s = new Stepper() {
#Override
public void step() throws Exception {
n += 1;
Thread.sleep(10);
}
};
PauseableThread t = PauseableThread.make(s);
// Start it up.
t.start();
Thread.sleep(1000);
t.pause();
System.out.println("Paused: " + n);
Thread.sleep(1000);
System.out.println("Resuminng: " + n);
t.resume();
Thread.sleep(1000);
t.cancel();
} catch (Exception e) {
}
}
}
Edit: Code modified to be of more general use.
Your best options are to either use wait()/notify() or to simply switch to ScheduledExecutorService
Proper wait()/notify() usage can be tricky. I highly recommend "Java Concurrency in Practice" to learn more about threading.
I believe the best way here would be to use Thread.wait for the waiting thread instead of sleeping, and use Thread.notify in the thread you are waiting for.
More info here:
http://www.javamex.com/tutorials/synchronization_wait_notify.shtml
You can improve efficiency drastic by using a monitor instead of sleeping the thread. You just make blocks in your code with a keyword synchronized. And an final Object that's acts the monitor. Look uP more in the API on monitors.