4

Hey there i currently have a problem with my android app. I´m starting an extra thread via implementing the Excecutor Interface:

class Flasher implements Executor {
    Thread t;
   public void execute(Runnable r) {
     t = new Thread(r){
     };
     t.start();
   }
 }

I start my Runnable like this:

flasherThread.execute(flashRunnable);

but how can i stop it?

Ian Nelson
  • 57,123
  • 20
  • 76
  • 103
TobiasPC
  • 41
  • 1
  • 1
  • 2
  • http://stackoverflow.com/questions/671049/how-do-you-kill-a-thread-in-java –  Dec 19 '12 at 18:37
  • 3
    Don't implement your own `Executor` without a very good reason to do so - use those already available in the Java API. Besides: Stopping a task performed in another thread in Java always relies on the other thread or rather its task to *cooperate*. If your `Runnable` keeps sitting in an endless loop, basically doing nothing, there is "no" way to stop it. – JimmyB Dec 19 '12 at 18:37
  • @ρяσѕρєяK There is no such method in the [Executor](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html) interface. – aymeric Dec 19 '12 at 18:40
  • possible duplicate of [How to stop a thread by another thread?](http://stackoverflow.com/questions/11839881/how-to-stop-a-thread-by-another-thread) – durron597 Dec 20 '12 at 01:30

4 Answers4

5

Ok, this is just the very basic threading 101, but let there be another example:

Old-school threading:

class MyTask implements Runnable {
    public volatile boolean doTerminate;

    public void run() {
        while ( ! doTerminate ) {
            // do some work, like:
            on();
            Thread.sleep(1000);
            off();
            Thread.sleep(1000);
        }
    }
}

then

MyTask task = new MyTask();

Thread thread = new Thread( task );

thread.start();

// let task run for a while...

task.doTerminate = true;

// wait for task/thread to terminate:
thread.join();
// task and thread finished executing

Edit:

Just stumbled upon this very informative Article about how to stop threads.

JimmyB
  • 12,101
  • 2
  • 28
  • 44
  • 1
    Java's standard way of interrupting a thread is... to interrupt the thread. And in your Runnable, you can use `while(!Thread.currentThread().isInterrupted()) {soSomething();}` to stop what you are doing when an interruption signal is sent. – assylias Dec 19 '12 at 23:26
  • 1
    Undoubtedly. - However, there still is *no* way to force an arbitrary `Runnable` (or thread) to terminate; in *every* case cooperation by the `Runnable` is required. And that's the point of the OP: To be able to stop a running thread, the code in that thread must be explicitly written to support that. – JimmyB Dec 20 '12 at 10:40
  • I'm not arguing about the cooperation bit - just saying that the cooperation is generally implemented with the interruption mechanism rather than boolean flags. – assylias Dec 20 '12 at 10:44
3

Not sure that implementing Executor is a good idea. I would rather use one of the executors Java provides. They allow you to control your Runnable instance via Future interface:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(flashRunnable);
...
future.cancel(true);

Also make sure you free resources that ExecutorService is consuming by calling executorService.shutdown() when your program does not need asynchronous execution anymore.

hoaz
  • 9,883
  • 4
  • 42
  • 53
  • "allow you to control your Runnable instance" - Sorry, but that is not true. They allow you to control the *`Executor`*, but the `Runnable` can still do whatever it likes, including not terminating and thus messing up the executor and what not. – JimmyB Dec 19 '12 at 18:40
  • 1
    `future.cancel()` method may return false, indicating that your cancel request has failed, but `Future` controls one single `Runnable` instance, not the `Executor` that may execute or schedule thousands of tasks – hoaz Dec 19 '12 at 18:43
  • So, how can one influence the `Runnable` instance via the `Future`? – JimmyB Dec 19 '12 at 18:44
  • Call `future.cancel(true)` and your `Runnable` instance will stop, if it is not designed to ignore `InterruptedException` – hoaz Dec 19 '12 at 18:48
  • 1
    The `Runnable`'s thread will be 'interrupted' - but that does not necessarily imply an `InterruptedException` will be thrown, or that there is any other effect on the `Runnable` instance at all. So, if the `Runnable` is not *explicitly prepared* to handle an externally set termination condition there is ["no"](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#stop%28%29) way to stop it. – JimmyB Dec 19 '12 at 18:58
  • Even your old school sample contains `sleep` call (that your forgot to handle, btw). That said, only _explicitly designed_ `Runnable` will not be interrupted, not the other way around. But this dispute deserves separate SO question. – hoaz Dec 19 '12 at 19:07
  • Yes, my example uses `sleep()` (omitting exception handling for simplicity). But there is no reason every `Runnable` will have to call any method that may throw an `InterruptedException`. What if I removed those calls to `sleep()`? - Unstoppable (by interruption) :) - And as you noted: *Explicit* handling of the `InterruptedException` would be required in a *correct* way to terminate. – JimmyB Dec 19 '12 at 19:10
  • If your `Runnable` does not have waiting calls (like sleep, wait or blocked IO), it will kill your application most probably, especially if it is long running job. If you ignore `InterruptedException`, this is what I called explicitly designed `Runnable`; and I consider it a bad practice too. – hoaz Dec 19 '12 at 19:20
  • Almost all blocking IO operations are *not* interruptible and, thus, will never throw `InterruptedException`s; special handling will be required. - Ignoring `InterruptedException`s - bad practice, definitely. Explicitly and correctly handling those exceptions - good practice, but no guarantee the thread will ever actually see the `InterruptedException` though `interrupt()`ed. – JimmyB Dec 19 '12 at 19:37
  • 1
    I did not say that it is guaranteed though. Still you can use `Thread.interrupted()` call to check if `interrupt()` was called instead of writing tones of old-school code – hoaz Dec 19 '12 at 19:40
  • Yes, that's absolutely correct; and the 'clean' way to do it. In this case, the `interrupted` state is the externally set 'flag'. – JimmyB Dec 20 '12 at 10:35
1

Instead of implementing your own Executor, you should look at ExecutorService. ExecutorService has a shutdown method which:

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.

tom
  • 18,953
  • 4
  • 35
  • 35
1

I would suggest to use the ExecutorService, along with the Furure object, which gives you control over the thread that is being created by the executor. Like the following example

ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(runnabale);
try {
     future.get(2, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
     Log.warn("Time out expired");
} finally {
     if(!future.isDone()&&(!future.isCancelled())) 
        future.cancel(true);

    executor.shutdownNow();
}

This code says that the runnable will be forced to terminate after 2 seconds. Of course, you can handle your Future ojbect as you wish and terminate it according to your requierements

pkran
  • 181
  • 1
  • 7