7

I am having an issue ending threads once my program my has finished. I run a threaded clock object and it works perfectly but I need to end all threads when the time ´==´ one hour that bit seems to work I just need to know how to end them. Here is an example of the code I have and this is the only thing that runs in the run method apart from one int defined above this code.

    @Override
    public void run()
    {
        int mins = 5;
        while(clock.getHour() != 1)
        {
            EnterCarPark();
            if(clock.getMin() >= mins)
            {
                System.out.println("Time: " + clock.getTime() + " " + entryPoint.getRoadName() + ": " + spaces.availablePermits() + " Spaces");
                mins += 5;
            }
        }
    }

But when you keep watching the threads that are running in the debug mode of netbeans they keep running after an hour has passed not sure how to fix this. I have tried the interrupt call but it seems to do nothing.

enter image description here

bobthemac
  • 1,172
  • 6
  • 26
  • 59
  • throw InterruptedException and catch it :) debugging will not be proper in multithreading program – Prashant Jan 23 '15 at 13:24
  • 1
    Are you sure the loop finishes? – Dawnkeeper Jan 23 '15 at 13:24
  • Yes I am sure the loop finishes – bobthemac Jan 23 '15 at 13:25
  • Please show the Thread class' attributes. Probably the garbage collector does not know when it can consume the thread objects. Also, you should investigate, in which way the threads are referenced. – SME_Dev Jan 23 '15 at 13:47
  • 1
    @SME the gc never collects running threads. – Voo Jan 23 '15 at 13:50
  • @Voo. I think, if there is an object that holds a strong reference to a thread, than this thread cannot be cleaned, even if it finished execution of its runnable code. – SME_Dev Jan 23 '15 at 13:56
  • 1
    @SME The same as with every other object, but that won't cause the thread to continue running. – Voo Jan 23 '15 at 15:02

7 Answers7

10

There are two ways to stop a thread in a nice way, and one in an evil way.

For all you need access to the object of the thread (or in the first case a Runnable class that is executed on that thread).

So your first task is to make sure you can access a list of all threads you want to stop. Also notice that you need to make sure you are using threadsafe communication when dealing with objects used by several threads!

Now you have the following options

Interrupt mechanisme

Call Thread.interrupt() on each thread. This will throw an InterruptedException on the thread if you are in a blocking function. Otherwise it will only set the isInterrupted() flag, so you have to check this as well. This is a very clean and versatile way that will try to interrupt blocking functions by this thread. However many people don't understand how to nicely react to the InterruptedException, so it could be more prone to bugs.

isRunning flag

Have a boolean 'isRunning' in your thread. The while loop calls a function 'stopRunning()' that sets this boolean to false. In your thread you periodically read this boolean and stop execution when it is set to false. This boolean needs to be threadsafe, this could be done by making it volatile (or using synchronized locking).

This also works well when you have a Runnable, which is currently the advised way of running tasks on Threads (because you can easily move Runnables to Threadpools etc.

Stop thread (EVIL)

A third and EVIL and deprecated way is to call Thread.stop(). This is very unsafe and will likely lead to unexpected behavior, don't do this!

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
Thirler
  • 20,239
  • 14
  • 63
  • 92
  • 1
    Additionally `Thread.stop()` is deprecated for just that reason. See [here](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#stop()) – Dawnkeeper Jan 23 '15 at 13:43
  • Ok where do I run the thread interrupt I have done it with the joins but the same thing happens I think I might need to work out how to throw because I keep getting an error that ´InterruptedException´ needs an import but I have the import. – bobthemac Jan 23 '15 at 13:45
  • 1
    "This will throw an InterruptedException on the thread" - it doesn't. It only does do in a few specific situations(blocking IO calls mostly) otherwise you have to check the flag yourself. For version 2 the flag has to be volatile. About version 3: Thread stop Knuth be thanked isn't working anymore in Java 7 or 8 iirc. – Voo Jan 23 '15 at 13:47
  • Thanks for your comments, I have updated the answer to reflect this. – Thirler Jan 23 '15 at 13:59
  • 3
    In fact, the `isRunning` flag is mostly redundant when you still got a hold on the `Thread` object, as `interrupt()` has that [same functionality](http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#isInterrupted--), plus some. Also note that many blocking operations are *not* interruptible, network (socket) IO for example, so other means will have to be used for these, like closing the socket from another thread. – JimmyB Jan 23 '15 at 16:13
  • @Hanno Good point, however the `isRunning` is used a lot because `Runnable` is preferred to `Thread` these days (and it is easier to grasp). – Thirler Jan 26 '15 at 08:40
2

Make sure that the loop inside every thread finishes - if it does in all the threads, it does not make sense that there are prints in the output. Just note that what you are checking in each loop condition check if the current hour is not 1 PM, not if an hour has not passed.

Also, your threads garbage collected, which means that the Garbage Collector is responsible for their destruction after termination - but in that case they should not output anything.

Nick Louloudakis
  • 5,856
  • 4
  • 41
  • 54
1

Have you considered using an ExecutorService ? It behaves more predictably and avoids the overhead of thread creation. My suggestion is that you wrap your while loop within one and set a time limit of 1 hr.

Toby Derrum
  • 299
  • 1
  • 3
  • 22
  • 1
    @Brandon ExecutorService behaves more predictably and avoids the overhead of thread creation. My suggestion is to simply wrap his while loop within one with a set time limit of 1 hr. – Toby Derrum Jan 23 '15 at 14:00
  • Right, my point was that your answer doesn't explain any of that. – Brandon Jan 23 '15 at 17:04
1

A volatile variable shared by all the Threads should help to achieve the goal. The importance of a volatile variable is that each of the Threads will not cache or have local copy but will need to directly read from the main memory. Once it is updated, the threads will get the fresh data.

    public class A{
     public static volatile boolean letThreadsRun = true;
    }

    // inside your Thread class
    @Override
    public void run()
    {    // there will come a point when A.letThreadsRun will be set to false when desired
         while(A.letThreadsRun)
        {

        }
    }

If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic.

Here are links that may help you to grasp the concept:

http://tutorials.jenkov.com/java-concurrency/volatile.html

http://java.dzone.com/articles/java-volatile-keyword-0

ZakiMak
  • 2,072
  • 2
  • 17
  • 26
1

If these threads are still running after your main program has finished, then it may be appropriate to set them as daemon threads. The JVM will exit once all non-daemon threads have finished, killing all remaining daemon threads.

If you start the threads like:

Thread myThread = new MyThread();
myThread.start();

Then daemon-izing them is as simple as:

Thread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
James_pic
  • 3,240
  • 19
  • 24
1

It's a bad practice to externally terminate threads or to rely on external mechanisms like kill for proper program termination. Threads should always be designed to self-terminate and not leave resources (and shared objects) in a potentially indeterminate state. Every time I have encountered a thread that didn't stop when it was supposed to, it was always a programming error. Go check your code and then step through the run loop in a debugger.

Regarding your thread, it should self-terminate when the hour reaches 1, but if it is below or above 1, it will not terminate. I would make sure that clock's hour count reaches one if minutes go past 59 and also check that it doesn't somehow skip 1 and increment off in to the sunset, having skipped the only tested value. Also check that clock.getHour() is actually returning the hour count instead of a dummy value or something grossly incorrect.

Jim W
  • 492
  • 2
  • 11
1

Using Thread.interrupt() will not stop the thread from running, it merely sends a signal to you thread. It's our job to listen for this signal and act accordingly.

Thread t = new Thread(new Runnable(){
              public void run(){
                 // look for the signal
                 if(!Thread.interrupted()){
                     // keep doing whatever you're doing
                 }

              }
         });

 // After 1 hour
 t.interrupt();

But instead of doing all this work, consider using an ExecutorService. You can use Executors class with static methods to return different thread pools.

Executors.newFixedThreadPool(10)

  • creates a fixed thread pool of size 10 and any more jobs will go to queue for processing later

Executors.newCachedThreadPool()

  • starts with 0 threads and creates new threads and adds them to pool on required basis if all the existing threads are busy with some task. This one has a termination strategy that if a thread is idle for 60 seconds, it will remove that thread from the pool

Executors.newSingleThreadExecutor()

  • creates a single thread which will feed from a queue, all the tasks that're submitted will be processed one after the other.

You can submit your same Runnable tasks to your thread pool. Executors also has methods to get pools to which you can submit scheduled tasks, things you want to happen in future

ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(myRunnableTask);

Coming to your question, when you use thread pools, you have an option to shut down them after some time elapsed like this

service.shutdown();
service.awaitTermination(60, TimeUnit.MINUTES);

Few things to pay attention

shutdown() Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.

awaitTermination() is waiting for the state of the executor to go to TERMINATED. But first the state must go to SHUTDOWN if shutdown() is called or STOP if shutdownNow() is called.

Arkantos
  • 6,530
  • 2
  • 16
  • 36