views:

236

answers:

5

I want to stop threads by using a boolean field. I have implemented some code to do this which is as follows:

My thread class is like this:

public class ParserThread implements Runnable {
    private volatile boolean stopped = false;

    public void stopTheThread() {
        stopped = true;
    }
    :
    :
}

And below is the main thread that starts 10 threads from the function start()

public class Main() {
    Thread [] threads;

    public void start() {
        for(int i = 0; i < 10; i++) {
            threads[i] = new Thread(new ParserThread());
        }       
    }

    public void stop() {
        // code to stop all the threads
    }
}

Now I want to call the stop method of the ParserThread to set "stopped = true" to stop the thread. I want this thing to be done for all the 10 threads.

How can I call that stop method. I want it to be done in the stopAllThreads() method of the Main class.

+5  A: 

You have to keep hold of the ParserThread objects themselves:

public class Main() {
    ParserThread[] parserthreads = new ParserThread[10];

    public void start() {
        for(int i = 0; i < 10; i++) {
            parserthreads[i] = new ParserThread();
            new Thread(parserthreads[i]).start();
        }       
    }

    public void stop() {
        for (int i = 0; i < 10; i++) {
            parserthreads[i].stopTheThread();
        }
    }
}

If you need the Thread objects themselves (e.g., to join() with them), either keep track of them separately, or have ParserThread inherit from Thread:

public class ParserThread extends Thread {
    private volatile boolean stopped = false;
    public void stopTheThread() {
        stopped = true;
    }
}

Also, as various others have pointed out, stopTheThread() uselessly duplicates the interrupt method on class Thread, so your best bet is:

public class Main() {
    Thread[] parserthreads = new Thread[10];

    public void start() {
        for(int i = 0; i < 10; i++) {
            parserthreads[i] = new Thread(new ParserThread());
            parserthreads[i].start();
        }       
    }

    public void stop() {
        for (int i = 0; i < 10; i++) {
            parserthreads[i].interrupt();
        }
    }
}

and then in ParserThread, call if (Thread.currentThread().isInterrupted()) as often as you can.

Grandpa
I want to call the stopTheThread() method of the thread class so as to set the field "stopped = true"
Yatendra Goel
Sorry, fixed that :)
Grandpa
NO NO NO! Don't ever call Thread.stop()! http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html#stop%28%29
Jason S
Right, you just fixed it.
Jason S
While this answer does address your original question, I think it's wrong (in the sense that you don't need that extra bunch of machinery, because Java already provides a cooperative interrupt()).
Jonathan Feinberg
Bah! This answer shouldn't have been accepted.
Jonathan Feinberg
+2  A: 

1) There's no need to have some extra volatile variable in order to signal your thread to stop; that's what interrupting is for. In the run() method of the threaded Runnable, you

while (!Thread.currentThread().isInterrupted()) {
    // do whatever your thing is
    // some things, like sleeping, can throw InterruptedException when
    // interrupted, so
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        break;
    }
}
// clean up here

2) Then, to ask your threaded process to stop, you simply

threads[i].interrupt();

Voilà.

Jonathan Feinberg
WARNING: there is a subtle difference between Thread.interrupted() and Thread.isInterrupted(). The former is a static method and resets the interrupted flag. The latter is nonstatic and does not reset the interrupted flag.
Jason S
Thank you! You're right, of course, and that's what I meant. Corrected.
Jonathan Feinberg
This assumes, of course, that all code properly handles and propagates InterruptedException, which a lot of code does not, thanks to the wonderful effect of checked exceptions causing naive programmers to just swallow them (myself included in the early days).
Software Monkey
SM, this is an example *showing* the correct handling of InterruptedException. How does this code assume anything?
Jonathan Feinberg
@Jonathan, Your original use of Thread.interrupted() was still valid as you were exitting the loop (and therefore presumably also exitting the run() method at this point); i.e. so It's probably more correct to reset the interrupt flag status in this case.
Adamski
You still run the risk of leaving the system in an inconsistent state the thread interrupts. For instance, if it interrupts class loading, that class will never load again in that class loader instance.
Tom Hawtin - tackline
@Jonathan Your code won't work because when a method throws an `InterruptedException`, it clears the interrupt status also. So the thread won't know about the interrupt status being set. To make this code work, you have to call the `Thread.currentThread().interrupt()` again in the catch block.
Yatendra Goel
@Jonathan I forgot to add one line to my previous comment that it won't work in nested loop case.
Yatendra Goel
+10  A: 

Take a look at the Executor framework. If you use an ExecutorService you can submit all your work as Runnables. The executor framework will keep track of all these threads, and all the managed threads will receive a shutdown request (interupt) via the shutdownNow() method.

Your threads will have to handle the interrupt properly. See this article for more information.

It's generally easier using the Executor framework to manage sets of threads, collect results, handle exceptions etc.

Brian Agnew
This is ultimately the correct answer, I think, although it's good to know about the information in mine, too. There aren't that many threading primitives in Java, and it's good to understand them, even if you're using Doug Lea's excellent util.concurrent stuff.
Jonathan Feinberg
@Brian: You beat me to it! ... Shouldn't have wasted time on a worked example! One thing - The API does not mention that shutDown() will issue any intterupts, but rather will wait for currently active tasks to complete. shutDownNow() will *typically* call interrupt().
Adamski
@Adamski - well spotted re. shutdownNow(). Now corrected. Thx
Brian Agnew
+6  A: 

Here is another alternative approach using an ExecutorService. It requires less code than manipulating Threads directly and offers two alternative methods of stopping the worker threads. It also allows you to potentially capture the results of each work item (if you were to use Callable instances instead of Runnables). Even if you did not wish to capture an explicit return value it allows you to easily marshall any exceptions back onto the main thread.

// Array of Runnables that we wish to process.
ParserThread[] parserThreads = ...

// Create executor service containing as many threads as there are Runnables.
// (Could potentially have less threads and let some work items be processed
// sequentially.)
ExecutorService execService = Executors.newFixedThreadPool(parserThreads.length);

// Submit each work item.  Could potentially store a reference to the result here
// to capture exceptions.
for (ParserThread runnable : parserThreads) {
  execService.submit(runnable);
}

Then to shut-down all threads you can either call:

executorService.shutDown(); // Initiates an orderly shut-down of the service.

... or

executorService.shutDownNow(); // Stops all tasks, interrupting waiting tasks.
Adamski
+1 for this one. We try very hard to never ever use bald Threads anymore. The new java.util.concurrency tools are just too useful to ignore and, as this question illustrates, bald Threads are awkward, confusing and sometimes dangerous.
Bob Cross
Funny, I thought all threads were *hairy* to work with.
Pedro Estrada
@Pedro - That's terrible! ... even for a Friday afternoon!
Adamski
+2  A: 
public class ParserThread implements Runnable {
private static volatile boolean stopped = false;

public static void stopTheThread() {
    stopped = true;
}

}

Declare stopped static and when you set it to false all ParserThread runnables will see the visibility.

Just invoke

ParserThread.stopTheThread();

Edit for the fact this will only affect the state of your stopped boolean flag. It will obviously not stop the threads for you :)

John V.