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.

4

4 回答 4

2

唯一的方法(行为良好的方法)是在生成的线程中添加逻辑点以检查中断状态。您可以选择使用内置Thread.interrupt()机制,或者使用某种形式的线程安全变量(AtomicBoolean?)或某种信号量添加您自己的逻辑。

如果您使用,Thread.interrupt()那么您的子进程在遇到某些条件时将抛出 InterruptedException,例如 Thread.wait() 和其他需要同步的方法或使用 java.util.concurrent.* 类。

InterruptedExceptions无论如何,您将需要(应该已经)处理线程,但也许您需要在子进程中进行常规“检查”以查找中断状态(可以使用Thread.isInterrupted()

这篇用 Java 处理 InterruptedException值得一读

于 2013-08-22T19:05:56.733 回答
1

如果你使用ExecutorService而不是原始线程,你最终会得到很多额外的方法/杠杆来控制你的线程,其中一个是shutdownAll()用来Thread.interrupt()杀死你的线程并让你通过检查线程状态isTerminated()

于 2013-08-22T19:07:57.750 回答
0

您的用户界面不必等待工作线程完成,所以不要太担心。

唉,Thread.destroy() 和 Thread.stop() 已被弃用,因为它们的实现不好。我认为没有一个好的“sig-kill”类型可以替代 Java 线程。如果很重要,您将不得不重新编码工人以检查某种中止标志。否则,就让它浪费一点CPU。(“你不能取消那个保存——我已经完成了!”,实际上)

于 2013-08-22T19:11:05.373 回答
0

是否可以取消任务实际上取决于它的实现。通常它会间歇性地检查一个标志是否应该继续。

您可以自己实现这样的标志,以及设置它的方法:

private volatile boolean shouldStop;

public void cancel() {
    shouldStop = true;
}

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

但是线程已经带有一个标志:中断标志。虽然它不一定用于取消线程,但通常将其用于该目的。事实上,标准ExecutorService实现会尝试通过中断线程来取消线程。

除此之外,当线程被中断时,几种阻塞方法(将线程置于BLOCKEDWAITING状态的方法)将抛出一个InterruptedException,此时它们RUNNABLE再次变为。这是以前使用布尔标志的方法无法实现的。

因此,使用中断来取消任务是一种更好的方法。而且您也不再需要该 cancel() 方法:

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

作为奖励,任何知道你的线程的代码都知道如何取消它。包括标准ExecutorService实现。

捕获 时应小心InterruptedException,因为这样做会清除中断标志。建议在捕获异常时始终恢复中断标志,因此客户端也知道是时候停止做他们正在做的事情了。

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();
        }

    }
}

要取消线程,您可以简单地保留对该Thread对象的引用并调用interrupt()它:

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

// some time after :

thread.interrupt();

但更优雅的方法是通过对象密切关注您的任务(而不是它运行的特定线程)Future。您可以通过将Runnableor包装CallableFutureTask.

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.

AFuture是控制任务的关键。它允许您等待其完成,并可选择接收任务计算的值:

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
}

如果您有多个任务(甚至只有一个),则值得使用 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.
于 2013-08-22T21:02:18.917 回答