Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How do you terminate a thread

0 views
Skip to first unread message

michael

unread,
Aug 21, 2001, 5:51:50 AM8/21/01
to
Hi All,

First I wanted to say a thank you to you all for tolerating my stupid
questions and giving such great answers. I really do research topics
before I ask a question on them and I answer 90% of my own question.
It is just that I am studying java about 12 hours a day right now and
so I inevitably come up with quite a few question that I can't answer
myself ion a reasonable amount of time without help.

Anyway, I just figured out how to simultaneously execute several
threads and control their priority. My test environment consist of a
gui to start a couple of threads when I push a button. It then prints
out stuff to indicate that the thread is running and I can see that I
have more than one thread running.

My problem is I want a button that I can click to get a particular
thread to terminate when I click it , just like I get the thread to
start when I click another button. I found the "stop" method under
thread but the method is deprecated and the Sun Documentation gives
some ominous warnings and advice:

"Note: the use of this method is unsafe as it can result in the
corruption of invariants. Stopping a thread with Thread.stop causes it
to unlock all of the monitors that it has locked (as a natural
consequence of the unchecked ThreadDeath exception propagating up the
stack). If any of the objects previously protected by these monitors
were in an inconsistent state, the damaged objects become visible to
other threads potentially resulting in arbitrary behaviour. Many uses
of stop should be replaced by code that simply modifies some volatile
variable to indicate that the target thread should stop running. The
target thread should check this variable regularly, and return from
its run method in an orderly fashion if the variable indicates that it
is to stop running. If the target thread waits for long periods, the
interrupt method should be used to interrupt the wait."


Does this mean that I should use the "return" keyword and a
conditional to exit the method that started the thread? I did this,
but then my application seemed unable to restart the thread. Here is
the code that I think is relavent. Unfortunately, I built this in the
Jbuilder and it creates a bunch of crap around the interesting code:


void jButton1_actionPerformed(ActionEvent e) {
System.out.println("hello world"); // This is a thread that I
simply call briefly to intrude on the counting thread I run below.

}

void jButton2_actionPerformed(ActionEvent e) {

ourCountThread.start();
}

void jButton3_actionPerformed(ActionEvent e) {
ourCountThread.viewCount();
}

void jButton4_actionPerformed(ActionEvent e) {
// I want to change the go variable in the start thread method to be
false.
ourCountThread.endCount();

}
}

class CountThread extends Thread {
int counter;
boolean go;
CountThread() {
this.setPriority(1);
counter=0;
}

public void run() { // This is the thread I want to start and run
till I deliberately stop it.
go=true;
while(go) {
counter++;
}
return; // This is where I try and end the thread. Does it just
terminate the method or does it terminate the thread?
}
public void viewCount() {
System.out.println(counter); // This the method I call to try and
see if the counter on the thread is incrementing. This function will
not work when I try and restart the thread.
}
public void endCount() {
go = false;
}
}

Jon Skeet

unread,
Aug 21, 2001, 6:36:09 AM8/21/01
to
michael <mic...@farheap.com> wrote:
> Does this mean that I should use the "return" keyword and a
> conditional to exit the method that started the thread?

Yes.

> I did this, but then my application seemed unable to restart
> the thread.

Indeed - threads can't be restarted when they've died. Note that your
"go" field needs to be volatile to make sure the VM doesn't just cache
it and never stop. (I personally always do this using synchronized
getters and setters, just for absolute safety.)

If you want to "restart" the thread, you either need to keep it around
(eg waiting on a monitor) or create a new thread which will do the same
thing, and start that.

--
Jon Skeet - <sk...@pobox.com>
http://www.pobox.com/~skeet/
If replying to the group, please do not mail me too

Jim Sculley

unread,
Aug 21, 2001, 9:49:12 AM8/21/01
to
michael wrote:

<snip Thread stuff>

>
>
> Does this mean that I should use the "return" keyword and a
> conditional to exit the method that started the thread? I did this,
> but then my application seemed unable to restart the thread.

That's because Threads cannot be restarted. Once the run() method
exits, the Thread is essentially dead. No hope for recovery. To
'continue' you must create a new Thread object.

Having said that, there is a fundamental flaw in your implementation
that needs to be addressed. Subclassing Thread is very rarely the
correct approach to dealing with threaded behavior. You aren't
extending/altering the behavior of the Thread class, you are simply
subclassing it to get at the run() method. This is totally unnecessary
because there is a Runnable interface designed to provide this without
extending Thread. If you have code that you want to run in a separate
Thread, you bundle it up in a Runnable object and pass that to a Thread
constructor. Here's you class using the Runnable approach, which,
incidentally, solves your problem as well:

public class Counter implements Runnable {
Thread runner;
int counter;
boolean shouldRun = false;
public synchronized void start() {
if (runner == null) {
runner = new Thread(this);
shouldRun = true;
runner.start();
}
}

public void stop() {
shouldRun = false;
runner = null;
}

public void viewCount() {
System.out.println(counter);
}

public void run() {
while (shouldRun) {
counter++;
}
}
}

Note that the start() method can be called repeatedly, and it will spawn
new threads only when necessary.

Jim S.

michael

unread,
Aug 21, 2001, 5:42:23 PM8/21/01
to
Thanks for your reply.

>
> Indeed - threads can't be restarted when they've died.

I do not understand why the language should be structure that way?
What would be dangerous about threads that could be restarted by
simply calling the run method on them again? Keeping the thread alive
but waiting would seem to me to be a waste of system reasources and a
problem if you wanted the thread to always restart in the same state.

Note that your
> "go" field needs to be volatile to make sure the VM doesn't just cache
> it and never stop.

Can you give an example of how I would make it volatile and be more
specific about why my code is in danger of not stopping? It seems to
stop.


(I personally always do this using synchronized
> getters and setters, just for absolute safety.)
>
> If you want to "restart" the thread, you either need to keep it around
> (eg waiting on a monitor) or create a new thread which will do the same
> thing, and start that.

Would I need to give subsequent threads different names? What should I
do if I want the thread to be stopped an restarted and arbitrary
number of times?

michael

unread,
Aug 21, 2001, 7:12:46 PM8/21/01
to
Jim Sculley <nic...@abraxis.com> wrote in message news:<3B8266D8...@abraxis.com>...
> michael wrote:

>
> Having said that, there is a fundamental flaw in your implementation
> that needs to be addressed.

Thanks, that is just the sort of thing I need to know about. When
studying a subject on your own, it is easy to figure out how to do
something that works, but not know that you are doing it in an
inelegant and potentially problematic way.

<snip>

>
> public class Counter implements Runnable {

It looks like by saying the class "implements Runnable" you are
declaring that that class has a method in it capable of starting a new
thread.

> Thread runner;

This looks like you are saying that the thread implemented when you
call this class should be referred to by the object label "runner".
This raises the question, Are threads objects or methods or something
else. It seems paradoxical that they can belong to an application, or
just be for a specific method in a class. Can they even be floating
all alone in the VM not attached to any application, method, or
class??


> int counter;
> boolean shouldRun = false;
> public synchronized void start() {

What is the purpose of the "synchronized" term here? What is the
thread synchronizing with?

> if (runner == null) {

Is a thread (in this case "runner") "null" when it has been
constructed but not yet started?

> runner = new Thread(this);

What is the purpose of passing the Thread constructor the arguement
"this", what else could be passed to it?

> shouldRun = true;
> runner.start();
> }
> }
>
> public void stop() {
> shouldRun = false;
> runner = null;
> }
>
> public void viewCount() {
> System.out.println(counter);
> }
>
> public void run() {
> while (shouldRun) {
> counter++;
> }
> }
> }
>
> Note that the start() method can be called repeatedly, and it will spawn
> new threads only when necessary.
>
> Jim S.

Thanks Again,

Michael

Jon Skeet

unread,
Aug 22, 2001, 3:31:43 AM8/22/01
to
michael <mic...@farheap.com> wrote:
> Thanks for your reply.
> >
> > Indeed - threads can't be restarted when they've died.
>
> I do not understand why the language should be structure that way?
> What would be dangerous about threads that could be restarted by
> simply calling the run method on them again? Keeping the thread alive
> but waiting would seem to me to be a waste of system reasources and a
> problem if you wanted the thread to always restart in the same state.

I don't see why it needs to be a waste of resources - what exactly would
you expect the difference to be at a low level, if the OS itself
supported restarting threads? (I suspect this is the main reason for
having them non-restartable - I don't know much about low-level
threading, but I would guess that many underlying thread implementations
aren't restartable either.)

> Note that your
> > "go" field needs to be volatile to make sure the VM doesn't just cache
> > it and never stop.
>
> Can you give an example of how I would make it volatile and be more
> specific about why my code is in danger of not stopping? It seems to
> stop.

It may well stop on your particular VM and machine, but there's no
guarantee that it will. To make it volatile, you just declare it
volatile:

volatile boolean go;

Your code is in danger because the VM may choose to cache the value of
go (say on a multi-processor machine) and never go back to the main
memory to find the new value. "volatile" means "this may be changed in
different threads, so please always check for the correct value".



> (I personally always do this using synchronized
> > getters and setters, just for absolute safety.)
> >
> > If you want to "restart" the thread, you either need to keep it around
> > (eg waiting on a monitor) or create a new thread which will do the same
> > thing, and start that.
>
> Would I need to give subsequent threads different names? What should I
> do if I want the thread to be stopped an restarted and arbitrary
> number of times?

You would wait on a monitor rather than actually stop the thread:

public void run()
{
while (!isReallyStopping())
{
doSomething();
synchronized (this)
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
}
}

where doSomething might *also* have a different condition flag. Then
when you want the thread to really die, you set whatever field
isReallyStopping tests.

Jon Skeet

unread,
Aug 22, 2001, 3:36:13 AM8/22/01
to
michael <mic...@farheap.com> wrote:
> > public class Counter implements Runnable {
>
> It looks like by saying the class "implements Runnable" you are
> declaring that that class has a method in it capable of starting a new
> thread.

Yes.

> > Thread runner;
>
> This looks like you are saying that the thread implemented when you
> call this class should be referred to by the object label "runner".
> This raises the question, Are threads objects or methods or something
> else. It seems paradoxical that they can belong to an application, or
> just be for a specific method in a class. Can they even be floating
> all alone in the VM not attached to any application, method, or
> class??

Threads are objects, that's all. The Thread.start() method performs a
bit of native wizardry that starts a different thread of execution at a
lower level, and creating a Thread will put it in a ThreadGroup. Other
than that (and the second isn't particularly magical) you can think of a
Thread as a normal Java object.

> > int counter;
> > boolean shouldRun = false;
> > public synchronized void start() {
>
> What is the purpose of the "synchronized" term here? What is the
> thread synchronizing with?

This object. By making start synchronized and checking for an existing
thread, Jim is making sure that starting it twice won't *actually* start
two different threads concurrently. The counter will only start again if
the previous thread had finished.

> > if (runner == null) {
>
> Is a thread (in this case "runner") "null" when it has been
> constructed but not yet started?

No, no Thread object has been constructed yet - it's just another normal
reference variable. Declaring
Thread runner;
doesn't create any Thread objects.



> > runner = new Thread(this);
>
> What is the purpose of passing the Thread constructor the arguement
> "this", what else could be passed to it?

A different Runnable instance, for one thing... there's nothing to say
that you have to run the class you're constructing a Thread from.

siphjand

unread,
Aug 22, 2001, 4:26:23 AM8/22/01
to
> public void stop() {
> shouldRun = false;
> runner = null;
> }
I think setting the runner to null is not very safe, because the thread object could

be garbage collected before the shouldRun condition was checked. I used
this for terminating a blocking thread in an IO operation (I had to
catch some exceptions). I don't know what happens to the locks, when the
thread is collected. If all locks are released, you have the same
problem as using the stop() method. If not, you have other problems!!
Philipp

Jon Skeet

unread,
Aug 22, 2001, 4:58:32 AM8/22/01
to
siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:
> > public void stop() {
> > shouldRun = false;
> > runner = null;
> > }
> I think setting the runner to null is not very safe, because the thread object could
> be garbage collected before the shouldRun condition was checked.

No it couldn't - if the thread is still running, it has a reference to
itself, so it can't be garbage collected.

(I would make stop synchronized though.)

> I used
> this for terminating a blocking thread in an IO operation (I had to
> catch some exceptions). I don't know what happens to the locks, when the
> thread is collected. If all locks are released, you have the same
> problem as using the stop() method. If not, you have other problems!!

I suspect your problems were elsewhere - just nulling a reference to a
thread won't make it be garbage collected.

Jim Sculley

unread,
Aug 22, 2001, 7:53:11 AM8/22/01
to
Jon Skeet wrote:
> michael <mic...@farheap.com> wrote:
>
>>>public class Counter implements Runnable {
>>>
>>It looks like by saying the class "implements Runnable" you are
>>declaring that that class has a method in it capable of starting a new
>>thread.
>>
>
> Yes.

And no. It is perfectly acceptable to have a class that implements
Runnable, but doesn't create any threads itself. You would then pass an
instance of this object to some other class that creates the thread.
Runnable simply means that the an instance of the class can be passed to
the Thread constructor which will then create a Thread in which the
run() method of the Runnable object can be executed.

Jim S.

Jon Skeet

unread,
Aug 22, 2001, 8:39:21 AM8/22/01
to

I do apologise - I misread it as "that class has a method in it which
makes it capable of being run in a new thread". Oops :)

Wayne Pollock

unread,
Aug 22, 2001, 9:55:41 AM8/22/01
to
Jon Skeet wrote:
>
> siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:
> > > public void stop() {
> > > shouldRun = false;
> > > runner = null;
> > > }
> > I think setting the runner to null is not very safe, because the thread object could
> > be garbage collected before the shouldRun condition was checked.
>
> No it couldn't - if the thread is still running, it has a reference to
> itself, so it can't be garbage collected.
>
> --
> Jon Skeet - <sk...@pobox.com>
> http://www.pobox.com/~skeet/
> If replying to the group, please do not mail me too

Actually a self-reference won't prevent Objects from being
garbage collected as far as I know. The GC works (in the abstract,
the implementation can be different; in fact I think the JDK GC will
change in v1.4?) by "marking" all Objects reachable from a small
set of "root" Objects. If those Objects refer to others, they
are marked as well. The process is recursive. After marking, all
non-marked Objects may be garbage collected (the "sweep" phase).
Note the actual implementation of the GC may not free up all
available memory each time it is run. Sometimes running System.gc()
several times in a row can free up more memory.

I think the reason Threads don't get garbage collected is that
a reference to them is maintained in a ThreadGroup Object, one
of the root Objects referred to previously. The ThreadGroup
maintains a reference to even dead Threads, so information about
them can be obtained. However I believe this design of Java
means that Thread Objects can never be garbage collected. As
this seems wrong to me, I bet I got it wrong, maybe someone
can straighten me out on this. (Maybe the ThreadGroup maintains
"weak" references?)

To reuse threads, you must manage them yourself and see that they
never actually die. Wrap the body of the run() method in such a way
that the Thread is suspended when finished. Such Threads go
into a list (the "Thread pool"). When a new Thread is needed,
first check the list. If empty you must create a new Thread,
but if not you can reuse the old one. Only be sure to re-initialize
the state (Object and ThreadLocal data).

-Wayne Pollock

Jon Skeet

unread,
Aug 22, 2001, 10:20:13 AM8/22/01
to
Wayne Pollock <pol...@acm.org> wrote:
> Jon Skeet wrote:
> >
> > siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:
> > > > public void stop() {
> > > > shouldRun = false;
> > > > runner = null;
> > > > }
> > > I think setting the runner to null is not very safe, because the thread object could
> > > be garbage collected before the shouldRun condition was checked.
> >
> > No it couldn't - if the thread is still running, it has a reference to
> > itself, so it can't be garbage collected.
>
> Actually a self-reference won't prevent Objects from being
> garbage collected as far as I know.

Sorry - you're right, it's the ThreadGroup that stops it from being
collected.

The important point is that a running Thread will *never* be garbage
collected.

> I think the reason Threads don't get garbage collected is that
> a reference to them is maintained in a ThreadGroup Object, one
> of the root Objects referred to previously. The ThreadGroup
> maintains a reference to even dead Threads, so information about
> them can be obtained. However I believe this design of Java
> means that Thread Objects can never be garbage collected. As
> this seems wrong to me, I bet I got it wrong, maybe someone
> can straighten me out on this. (Maybe the ThreadGroup maintains
> "weak" references?)

I would certainly hope they're weak or soft, yes. I don't know what they
did before 1.2...

Patricia Shanahan

unread,
Aug 23, 2001, 1:46:56 AM8/23/01
to

Jon Skeet wrote:
>
> Wayne Pollock <pol...@acm.org> wrote:
> > Jon Skeet wrote:
> > >
> > > siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:
> > > > > public void stop() {
> > > > > shouldRun = false;
> > > > > runner = null;
> > > > > }
> > > > I think setting the runner to null is not very safe, because the thread object could
> > > > be garbage collected before the shouldRun condition was checked.
> > >
> > > No it couldn't - if the thread is still running, it has a reference to
> > > itself, so it can't be garbage collected.
> >
> > Actually a self-reference won't prevent Objects from being
> > garbage collected as far as I know.
>
> Sorry - you're right, it's the ThreadGroup that stops it from being
> collected.
>
> The important point is that a running Thread will *never* be garbage
> collected.

...

Another way of looking at it is to go back to the basic definition of
"reachable". The method Thread.currentThread() makes any running Thread
object accessible to the code it is running, so it is reachable, and
cannot be garbage collected.

Patricia

siphjand

unread,
Aug 23, 2001, 6:53:19 PM8/23/01
to
Jon Skeet wrote:
> siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:
>
>>> public void stop() {
>>> shouldRun = false;
>>> runner = null;
>>> }
>>>
>>I think setting the runner to null is not very safe, because the thread object could
>>be garbage collected before the shouldRun condition was checked.
>>
>
> No it couldn't - if the thread is still running, it has a reference to
> itself, so it can't be garbage collected.
>
> (I would make stop synchronized though.)
>
>
>>I used
>>this for terminating a blocking thread in an IO operation (I had to
>>catch some exceptions). I don't know what happens to the locks, when the
>>thread is collected. If all locks are released, you have the same
>>problem as using the stop() method. If not, you have other problems!!
>>
>
> I suspect your problems were elsewhere - just nulling a reference to a
> thread won't make it be garbage collected.

I attached my class, where I used nulling the thread reference. The
problem was, that I had to start another native program as a separate
process and display its stdout to a window. So I read it using a
separate thread and the readline() method. But I wanted to close the
stdout window before the process exited especially when there was no
output on stdout (and the readline method blocked). I didn't want to use
stop() since it is deprecated (I hate compiler warnings) and setting the
thread to null worked (without setting it to null, I had to wait for the
next line of output before the thread would have stopped, because the
stop condition is checked between the readline() calls).
I was very proud, that I found this solution.


OutputDialog.java

siphjand

unread,
Aug 24, 2001, 3:32:59 AM8/24/01
to


Oops!!
ok, I nulled the inputstream. Sorry!

Jon Skeet

unread,
Aug 24, 2001, 4:05:42 AM8/24/01
to
siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:

> I attached my class, where I used nulling the thread reference. The
> problem was, that I had to start another native program as a separate
> process and display its stdout to a window. So I read it using a
> separate thread and the readline() method. But I wanted to close the
> stdout window before the process exited especially when there was no
> output on stdout (and the readline method blocked). I didn't want to use
> stop() since it is deprecated (I hate compiler warnings) and setting the
> thread to null worked (without setting it to null, I had to wait for the
> next line of output before the thread would have stopped, because the
> stop condition is checked between the readline() calls).
> I was very proud, that I found this solution.

Unfortunately you don't seem to have understood your solution. You're
never setting your *thread* to null - you're setting *pin* to null. This
is making pin.readLine() throw a NullPointerException (which you
probably don't see), but it should only be doing it at the next call to
readLine()... I suspect it's only *actually* stopping at the next
readLine anyway.

Of course, I may have read your code - which line did you think was
setting the thread reference to null?

siphjand

unread,
Aug 24, 2001, 5:47:09 AM8/24/01
to
Jon Skeet wrote:

> Unfortunately you don't seem to have understood your solution. You're
> never setting your *thread* to null - you're setting *pin* to null.

Yes, I noticed. Has been a long time ...


> This is making pin.readLine() throw a NullPointerException (which you
> probably don't see), but it should only be doing it at the next call
> to readLine()... I suspect it's only *actually* stopping at the next
> readLine anyway.

No! It immediately stops reading from the stream!


> Of course, I may have read your code - which line did you think was
> setting the thread reference to null?

s.a.
>


Jon Skeet

unread,
Aug 24, 2001, 7:06:25 AM8/24/01
to
siphjand <siph...@stud.informatik.uni-erlangen.de> wrote:

> > This is making pin.readLine() throw a NullPointerException (which you
> > probably don't see), but it should only be doing it at the next call
> > to readLine()... I suspect it's only *actually* stopping at the next
> > readLine anyway.

> No! It immediately stops reading from the stream!

I'm afraid I don't believe that, as there's no reason it should. If it's
actually within the method call at the time that you null the reference,
it should make no difference to it.

I'll try to knock up a program to demonstrate that if you want.

0 new messages