18

I have an multiple-threaded java project and I want to add a method stop() to stop all the running threads. The problem is that this project is developed by someone else, and I am not familiar with how it implements multiple threads.

What I know is that once the project get started, many threads are invoked and they run forever. Is there a way to find all running threads and stop them? I have searched a lot, and found how to get a list of running threads:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();

What to do next to stop all the running threads?

The reason why I want to stop these threads is that I need to deploy this project to OSGi container as a bundle. Once the bundle is started, multiple threads run forever. So I need to implement a destroy() method to stop all threads to control the bundle lifecycle.

How about

for (Thread t : Thread.getAllStackTraces().keySet()) 
{  if (t.getState()==Thread.State.RUNNABLE) 
     t.interrupt(); 
} 

for (Thread t : Thread.getAllStackTraces().keySet()) 
{  if (t.getState()==Thread.State.RUNNABLE) 
     t.stop(); 
}
Li'
  • 3,133
  • 10
  • 34
  • 51
  • why do you want to stop all threads? If you all looking to stop your application then System.exit is the right choice. – Ankit Bansal Mar 25 '13 at 20:42
  • Don't try to stop all threads. There's a reason why the stop() of `Thread` has been deprecated. Have a look at the documentation: http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#stop() – Darwind Mar 25 '13 at 20:43
  • @Ankit Because I need to deploy this project to OSGi container as a bundle. Once the bundle is started, multiple threads run forever. So I need to implement a destroy() method to stop all threads to control the bundle lifecycle. – Li' Mar 25 '13 at 20:56
  • can't you use OSGi bundle stop method itself. I don't know much about OSGi, ignore my comment if not that useful. – Ankit Bansal Mar 25 '13 at 21:14
  • @Ankit That is what I wish to find out. But so far what I know is you need to implement the stop() method by yourself – Li' Mar 25 '13 at 21:19
  • 1
    Why are there threads that run forever? Are they threads you create? – dimo414 Mar 25 '13 at 21:39
  • @dimo414 presumably because they need to run forever. This is far from an unusual pattern. – Martin James Mar 26 '13 at 10:05
  • I don't know about that. Threads that run forever are usually either daemon threads or provide some other way of controlling them. A program which starts threads and provides no way to stop them seems concerning to me. – dimo414 Mar 26 '13 at 12:57
  • @dimo414 they probably are daemon threads. Also, you worry too much :) – Martin James Mar 26 '13 at 15:38
  • If they're daemon threads, they'll terminate sanely without intervention by the OP. – dimo414 Mar 26 '13 at 16:20

3 Answers3

21

This is a dangerous idea. The Javadoc for Thread.stop() explains:

This method is inherently unsafe. 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 behavior. Many uses of stop should be replaced by code that simply modifies some 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 (on a condition variable, for example), the interrupt method should be used to interrupt the wait.

Fundamentally, threads need to be built and designed to safely terminate, it is not possible to safely kill arbitrary threads. A fairly standard pattern is implemented like so:

public abstract class StoppableRunnable implements Runnable {
    private volatile boolean stopWork;
    private boolean done;

    public final void run() {
        setup();
        while(!stopWork && !done) {
            doUnitOfWork();
        }
        cleanup();
    }

    /**
     * Safely instructs this thread to stop working,
     * letting it finish it's current unit of work,
     * then doing any necessary cleanup and terminating
     * the thread.  Notice that this does not guarentee
     * the thread will stop, as doUnitOfWork() could
     * block if not properly implemented.
     */
    public void stop() {
        stopWork = true;
    }

    protected void done() {
        done = true;
    }

    protected void setup() { }
    protected void cleanup() { }

    /**
     * Does as small a unit of work as can be defined
     * for this thread.  Once there is no more work to
     * be done, done() should be called.
     */
    protected abstract void doUnitOfWork();
}

You implied you aren't the author of these threads, which suggest they may not be safely stoppable. In such a case, you can call Thread.interrupt() to instruct the thread to stop what it's doing (instead of the pattern described above, you could use Thread.interrupt() to similar effect) however similarly, if the thread's designer hasn't written it to handle interrupts, this may not do anything or cause inconsistent states or other errors.

Ultimately, Thread.stop() is what you want if you just want to "[Force] the thread to stop executing" and can't modify the thread's implementation; however like using kill in Unix, this is a dangerous proposition, and you should essentially consider your JVM to be in an unstable and irreparable state after terminating a thread in this way, and attempt to exit the program as quickly as possible thereafter.


Regarding your suggestion of interrupting then stopping:

There's still a lot of problems here, in particular, interrupting does not guarantee the thread will interrupt immediately (it works similarly, though less explicitly, to my StoppableRunnable above) and instead sets a flag that the thread should interrupt when possible. This means you could call Thread.interrupt(), the thread could start it's proper interrupt-handling behavior, then midway through that, your call to Thread.stop() fires, violently killing the thread and potentially breaking your JVM. Calls to Thread.interrupt() provide no guarantee as to when or how the thread will respond to that interrupt, which is why I prefer the explicit behavior in StoppableRunnable. Needless to say, if you're ever going to call Thread.stop() there's little to be gained by calling Thread.interrupt() first. I don't recommend it, but you might as well just call Thread.stop() in the first place.

Additionally, recognize that the code running your loop is itself in a thread - meaning your loop could very well kill itself first, leaving all other threads running.

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
dimo414
  • 47,227
  • 18
  • 148
  • 244
  • can I try this: for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getState()==Thread.State.RUNNABLE) t.interrupt(); } for (Thread t : Thread.getAllStackTraces().keySet()) { if (t.getState()==Thread.State.RUNNABLE) t.stop(); } – Li' Mar 25 '13 at 21:07
  • If I'm reading that right (better to update your question than post code in comments) that should give you the number of running threads, yes. It won't stop any of them though... – dimo414 Mar 25 '13 at 21:09
  • in the first for() loop, i call t.interrupt() to instruct the thread to stop. in the second for() loop, i call t.stop() to stop the thread. I know this is a bad idea, but I have no other choice since I am not the author to create these threads – Li' Mar 25 '13 at 21:13
  • Difficult for me to follow what you're trying to do when you keep editing comments. Please update your question if you have additional information. You can certainly give that a try, like I said in my answer, calling `Thread.stop()` is inherently dangerous, and likely to leave your application in a broken state. If that's acceptable to you, go for it, but don't be surprised when you start seeing unusual / difficult to debug errors and behavior. – dimo414 Mar 25 '13 at 21:17
  • Updated my answer to address your suggested behavior - needless to say, it's not a good idea. – dimo414 Mar 25 '13 at 21:32
  • Thanks for your explicit explanation. I wish I can figure out how these threads are implemented and add thread-safe control codes there. – Li' Mar 25 '13 at 21:52
  • That certainly would be the right thing to do. What exactly is creating these threads, and why do they run forever? I don't know OSGi, but it surprises me that any sort of legitimate library would be creating threads that never terminate, and prevent your application from terminating. – dimo414 Mar 25 '13 at 22:07
  • Your stopWork and done are not properly synchronized. You should make them volatile or AtomicBoolean. – Peter Kriens Mar 26 '13 at 07:12
  • @dimo414 OSGi certainly doesn't create threads that never terminate. The problem is the junk code that people bring with them when they start using OSGi! Really great in-depth answer by the way, one of the best I've seen on SO. – Neil Bartlett Mar 26 '13 at 10:39
  • @PeterKriens is that necessary in this case? Since `stopWork` and `done` are both private variables, and can never be set back to true, is there actually a risk of race conditions here? Will update if so, but I've used this pattern on personal projects without issue. – dimo414 Mar 26 '13 at 12:55
  • 1
    It is not about race conditions. Each thread can run on its own core and use its caches. Only when you pass a memory barrier (volatile read or write, and synchronized) are these caches synchronized. So If you are in a thread and check a private var which is changed on another thread you will never see it on a multi-core. Brian Goetz's book on Concurrency gives a good explanation. – Peter Kriens Mar 26 '13 at 13:50
  • Interesting, never run into that, but will update with AtomicBoolean. – dimo414 Mar 26 '13 at 13:57
  • I would personally change this code as follows. First, use Thread.interrupt() to signal the interrupt, and then the loop should call Thread.interrupted() to find out whether interrupt has occurred. Then `doUnitOfWork()` should also throw `InterruptedException` which should pull us out of the loop. Finally doUnitOfWork could return a boolean to signal "done", rather than setting a variable off to the side. – Neil Bartlett Mar 27 '13 at 18:45
  • Like I mentioned, you could use `Thread.interrupt()`. Personally, I prefer to explicitly implement a separate stop behavior, but your method is absolutely viable. – dimo414 Mar 27 '13 at 19:22
  • @PeterKriens is incorrect on x86/x64. All that needs to happen is a write to memory, not to a register. The "memory" barrier for those platforms with setOrderedXXX and getVolatileXXX is a NOOP but it forces the compiler to issue an actual read/write (e.g. mov instruction) to memory. No actual membar instruction is issued. setVoltaileXXX issues a full membar, with the corresponding instruction. – Eloff Apr 06 '14 at 01:13
1

I used this code:

package com.xxx;

import com.xxx.tools.messageLog;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Mostafa Nazari
 */
public class ProcessAgent extends Thread{

    public ProcessAgent() {
        super("Process-Agent");
    }


    @Override
    public void run() {
        try {
            com.xxx.Process.agent.Main.main(new String[]{});
        } catch (Exception ex) {
            if (ex instanceof InterruptedException) {
                messageLog.stdwar("Process Agent Stopped");
            }else {
                messageLog.stderr("FATAL Error: "+ex.getMessage());
                Logger.getLogger(ProcessAgent.class.getName()).log(Level.SEVERE, null, ex);            
            }
        }    
    }

    public void terminate() {
        if (super.isAlive()) {
            ThreadGroup group = super.getThreadGroup();
            while (group != null) {
                group .interrupt();
                group = super.getThreadGroup();
            }
            super.interrupt();
        }
    }

    public String getStatus() {
        if (super.isAlive()) {
            return "running";
        } else {
            if (super.isInterrupted()) 
                return "stopping";
            else
                return "stopped";
        }
    }

}

hope it is useful for this issue

Mostafa Nazari
  • 616
  • 7
  • 21
0

Instead of creating normal Thread, use advanced concurrent API like ExecutorService or ThreadPoolExecutor

You can have a look at different APIs in this post:

Java's Fork/Join vs ExecutorService - when to use which?

Refer to below SE questions for forced shut down of ExecutorService:

How to forcefully shutdown java ExecutorService

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211