2

I have a situation where I'm using a Thread, she call a method that will do multiple processes, I need to use a "cancel" button in which you have to stop the thread, I not can use: "while" ,to verify that it was canceled because it not has loop in this process.

Ex:

    Task<Void> task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            controller = new FirstEtapaController();
            execProcess();              
            return null;
        }
    };
    new Thread(task).start();

Call Method

   private void execProcess() {
   Thread thread = new Thread(new Runnable() {

        public void run() {
    getController().execMhetod();
    refreshTable();
        }
    });
    thread.start();
    thread.join();
};

Ie, I need to stop this process, even when the "ExecMethod" already running, it will take minutes, so I've gotta stop it and not have to wait for him to finish so that , others do not continues.

Remembering that this process will do iteration with my DAO.

Giovane
  • 753
  • 4
  • 9
  • 15
  • 2 things: the way you have it now, the method `call()` will return almost immediately, it won't wait until `execProcess()` is done. And also, the best way to stop a thread is to use a flag and check it after every step. The thread should be the one to exit, an outside request shouldn't be killing the thread. – Daniel Gabriel Aug 22 '13 at 19:03
  • Searching for `[java] Thread interrupt` did not tell you what you wanted to know? – Raedwald Aug 22 '13 at 21:36

4 Answers4

2

The only way (well behaved way) is to add logic points in you spawned threads to check for an interrupted state. You can choose to use the built-in Thread.interrupt() mechanisms, or add your own logic using some form of thread-safe variable (an AtomicBoolean?) or a Semaphore of some sort.

If you use the Thread.interrupt() then your child processes will throw an InterruptedException when they encounter certain conditions, like Thread.wait() and other methods which require synchronization or use the java.util.concurrent.* classes.

You will need to (should already be) handle the InterruptedExceptions in the threads anyway, but perhaps you will need to put regular 'checks' in your child processes to look for the interrupted state anyway (can use Thread.isInterrupted() )

It is worth reading this Handling InterruptedException in Java

Community
  • 1
  • 1
rolfl
  • 17,539
  • 7
  • 42
  • 76
  • Interrupt is just a flag that some Java methods are affected by, but not many. If you need reliability then you need to check the status yourself. – rolfl Aug 22 '13 at 19:19
1

If instead of a raw Thread if you use an ExecutorService you'll end up with lots of additional methods/levers to control your threads, one of which is shutdownAll() which uses Thread.interrupt() to kill your thread and lets you check thread status via isTerminated()

Paul Rubel
  • 26,632
  • 7
  • 60
  • 80
  • 2
    Your interrupted thread still has to check itself to see if it has been interrupted though (either through one of the methods that throws InterruptedException, or through a check to Thread.isInterrupted(). – rolfl Aug 22 '13 at 19:28
  • This works, but only in the next process, if it is already running, it does not stop the process. Only the next. – Giovane Aug 23 '13 at 16:57
0

Your user interface does not have to wait for the worker thread to finish, so don't worry too much about that.

Alas, Thread.destroy() and Thread.stop() are deprecated, due to bad implementations. I don't think there is a good "sig-kill" type of substitute for Java threads. You are going to have to recode the worker to check an abort flag of some kind, if it matters much. Otherwise, just let it waste a little CPU. ("you can't cancel that Save -- I've already done it!", in effect)

Roboprog
  • 3,054
  • 2
  • 28
  • 27
0

Whether or not a task can be canceled really depends on its implementation. Typically it intermittently checks a flag whether it should continue or not.

You can implement such a flag yourself, and a method to set it :

private volatile boolean shouldStop;

public void cancel() {
    shouldStop = true;
}

@Override
public void run() {
    while (!shouldStop) {
        // do work
    }
}

But threads already come with a flag : the interrupted flag. And while it is not necessarily used for canceling a thread, it is typical to use it for exactly that purpose. In fact the standard ExecutorService implementations will try to cancel their threads by interrupting them.

Aside from that several blocking methods (methods that put a thread in BLOCKED or WAITING state) will throw an InterruptedException when the thread is interrupted, at which point they become RUNNABLE again. This is something the previous approach with a boolean flag cannot achieve.

Therefore it is a better approach to use interruption to allow a task to be canceled. And you do not really need that cancel() method any more either :

@Override
public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        // do work
    }
}

As a bonus, any code that knows your thread, knows how to cancel it. Including standard ExecutorService implementations.

Care should be taken when catching an InterruptedException, since doing that clears the interrupted flag. It is adviseable to always restore the interrupted flag when catching the Exception, so clients also know it's time to stop doing what they're doing.

private BlockingQueue<Integer> queue;

@Override
public void run() {
    while (!Thread.currentThread().isInterrupted()) {

        try {
            Integer id = queue.take(); // blocking method

            // do work
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

    }
}

To cancel a thread, you can simply keep a reference to the Thread object and call interrupt() on it :

Thread thread = new Thread(new InterruptibleTask());
thread.start();

// some time after :

thread.interrupt();

But a more elegant approach is keeping tabs on your task (and not so much the specific thread it runs on) through a Future object. You can do this by wrapping your Runnable or Callable in a FutureTask.

RunnableFuture<Void> task = new FutureTask<>(new InterruptibleTask(), null);
new Thread(task).start();

// some time after :

task.cancel(true); // true indicating interruption may be used to cancel.

A Future is key in controlling your task. It allows you to wait for its completion, and optionally receive a value the task calculated :

try {
    String value = future.get(); // return value is generically typed String is just as example.
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // since future.get() blocks
} catch (ExecutionException e) {
    logger.log(Level.SEVERE, "Exception on worker thread", e.getCause()); // the ExecutionException's cause is the Exception that occurred in the Task
}

If you have several tasks (or even just one) it is worth using an ExecutorService :

ExecutorService pool = Executors.newCachedThreadPool();

Future<?> submit = pool.submit(new InterruptibleTask());

pool.shutdownNow(); // depending on ExecutorService implementation this will cancel all tasks for you, the ones Executors returns do.
bowmore
  • 10,842
  • 1
  • 35
  • 43