views:

1275

answers:

8

I am having a real hard time finding a way to start, stop, and restart a thread in Java.

Specifically, I have a class Task (currently implements Runnable) in a file Task.java. My main application needs to be able to START this task on a thread, STOP (kill) the thread when it needs to, and sometimes KILL & RESTART the thread ...

My first attempt was with ExecutorService but I can't seem to find a way for it restart a task. When I use .shutdownnow() any future call to .execute(..) fails because the ExecutorService is "shutdown"...

So, how could I accomplish this? Any help would be greatly appreciated.... Thanks,

+1  A: 

Once a thread stops you cannot restart it. However, there is nothing stopping you from creating and starting a new thread.

Option 1: Create a new thread rather than trying to restart.

Option 2: Instead of letting the thread stop, have it wait and then when it receives notification you can allow it to do work again. This way the thread never stops and will never need to be restarted.

Edit based on comment:

To "kill" the thread you can do something like the following.

yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
Taylor Leese
Sadly I must kill/restart it ... I don't have complete control over the contents of the thread and for my situation it requires a restart...So, creating a new one is fine ... but how do I kill the current one first?
Shaitan00
If you really wanted to 'kill' the thread never rely or attempt to use any of the api methods that seem to do that, for example kill() stop() destroy(). Instead, as Taylor suggested look at the interrupted flag: while(!Thread.currentThread().isInterrupted()){ ... } When the thread is interrupted, clean up any functions in that thread and return out of the run method and start a new thread.
John V.
I assume there is a loop in your thread so it can check a flag to see if the thread should stop or continue executing.
Taylor Leese
A: 

There's a difference between pausing a thread and pausing it. If stopping for you mean killing the thread, then a restart simply means creating a new thread and launching.

There are methods for killing threads from a different thread (e.g., your spawner), but they are unsafe in general. It might be safer if your thread constantly checks some flag to see if it should continue (I assume there is some loop in your thread), and have the external "controller" change the state of that flag.

You can see a little more in: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

May I ask why you want to kill the thread and restart it? Why not just have it wait until its services are needed again? Java has synchronization mechanisms exactly for that purpose. The thread will be sleeping until the controller notifies it to continue executing.

Uri
A: 

If your task is performing some kind of action in a loop there is a way to pause/restart processing, but I think it would have to be outside what the Thread API currently offers. If its a single shot process I am not aware of any way to suspend/restart without running into API that has been deprecated or is no longer allowed.

As for looped processes, the easiest way I could think of is that the code that spawns the Task instantiates a ReentrantLock and passes it to the task, as well as keeping a reference itself. Every time the Task enters its loop it attempts a lock on the ReentrantLock instance and when the loop completes it should unlock. You may want to encapsulate all this try/finally, making sure you let go of the lock at the end of the loop, even if an exception is thrown.

If you want to pause the task simply attempt a lock from the main code (since you kept a reference handy). What this will do is wait for the loop to complete and not let it start another iteration (since the main thread is holding a lock). To restart the thread simply unlock from the main code, this will allow the task to resume its loops.

To permanently stop the thread I would use the normal API or leave a flag in the Task and a setter for the flag (something like stopImmediately). When the loop encountered a true value for this flag it stops processing and completes the run method.

Gennadiy
Sadly the thread is waiting (listening) for incomming traffic, it is a blocking synchronous event ... so there is no "loop"
Shaitan00
+1  A: 

Review java.lang.Thread.

To start or restart (once a thread is stopped, you can't restart that same thread, but it doesn't matter; just create a new Thread instance):

// Create your Runnable instance
Task task = new Task(...);

// Start a thread and run your Runnable
Thread t = new Thread(task);

To stop it, have a method on your Task instance that sets a flag to tell the run method to exit; returning from run exits the thread. If your calling code needs to know the thread really has stopped before it returns, you can use join:

// Tell Task to stop
task.setStopFlag(true);

// Wait for it to do so
t.join();

Regarding restarting: Even though a Thread can't be restarted, you can reuse your Runnable instance with a new thread if it has state and such you want to keep; that comes to the same thing. Just make sure your Runnable is designed to allow multiple calls to run.

T.J. Crowder
Sadly the thread is waiting (listening) for incomming traffic, it is a blocking synchronous event ... so there is no "loop" within run...
Shaitan00
@Shaitan00: If you're talking about a `ServerSocket` blocking on an `accept` call, then just have your `setStopFlag` call `close` on the socket. The `accept` call will unblock by throwing a `SocketException`. Anything else that blocks will almost certainly have an analogous exit mode.
T.J. Crowder
A: 

As stated by Taylor L, you can't just "stop" a thread (by calling a simple method) due to the fact that it could leave your system in an unstable state as the external calling thread may not know what is going on inside your thread.

With this said, the best way to "stop" a thread is to have the thread keep an eye on itself and to have it know and understand when it should stop.

JasCav
But the thread itself is blocking on a .receive listening for network traffic... it doesn't actually loop until it recieves something....So, send it a dummy message to "kick the loop into gear" and set a flag?
Shaitan00
A: 

Based on the responses in comments from the OP I figure I will post my response. As mentioned you cannot restart a thread as the java API will not allow it. You do not want to kill a thread using any of the deprecated public API methods in the Thread class as they are deprecated for a very good reason.

What you want to do, is since your thread is blocking, seemingly interruptibility, then interrupt the thread. So when you want to stop the thread that is blocking:

  thread = threadYouWantToStop;
  thread.interrupted();

Within the thread that is blocking just catch for an InterruptedException, clean up safely anything in the thread. Then return out and start a new thread.

John V.
A: 

You can't restart a thread so your best option is to save the current state of the object at the time the thread was stopped and when operations need to continue on that object you can recreate that object using the saved and then start the new thread.

These two articles Swing Worker and Concurrency may help you determine the best solution for your problem.

ChadNC
+1  A: 

It is impossible to terminate a thread unless the code running in that thread checks for and allows termination.

You said: "Sadly I must kill/restart it ... I don't have complete control over the contents of the thread and for my situation it requires a restart"

If the contents of the thread does not allow for termination of its exectuion then you can not terminate that thread.

In your post you said: "My first attempt was with ExecutorService but I can't seem to find a way for it restart a task. When I use .shutdownnow()..."

If you look at the source of "shutdownnow" it just runs through and interrupts the currently running threads. This will not stop their execution unless the code in those threads checks to see if it has been ineterrupted and, if so, stops execution itself. So shutdownnow is probably not doing what you think.

Let me illustrate what I mean when I say that the contents of the thread must allow for that thread to be terminated:

myExecutor.execute(new Runnable() {
 public void run() {
  while (true) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

That thread will continue to run forever, even though shutdownnow was called, because it never checks to see if it has been terminated or not. This thread, however, will shut down:

myExecutor.execute(new Runnable() {
 public void run() {
  while (!Thread.interrupted()) {
    System.out.println("running");
  }
 }
 });
myExecutor.shutdownnow();

Since this thread checks to see whether or not it has been interrupted / shut down / terminated.

So if you want a thread that you can shut down, you need to make sure it checks to see if it has been interrupted. If you want a thread that you can "shut down" and "restart" you can make a runnable that can take new tasks as was mentioned before.

Why can you not shut down a running thread? Well I actually lied, you can call "yourThread.stop()" but why is this a bad idea? The thread could be in a synchronized (or other critical section, but we will limit ourselves to setions guarded by the syncrhonized key word here) section of code when you stop it. synch blocks are supposed to be executed in their entirity and only by one thread before being accessed by some other thread. If you stop a thread in the middle of a synch block, the protection put into place by the synch block is invalidated and your program will get into an unknown state. Developers make put stuff in synch blocks to keep things in synch, if you use threadInstance.stop() you destroy the meaning of synchronize, what the developer of that code was trying to accomplish and how the developer of that code expected his synchronized blocks to behave.

mlaw