取消java中的未来任务

gau*_*tam 5 java multithreading exception executorservice futuretask

我想取消提交给ExecutorService的任务,从而允许相应的线程从队列中选择一个新任务.

现在这个问题已在这个论坛上多次回答....比如检查Thread.currentThread().interrupt()catch (InterruptedException e).但是,如果控制流跨越多种方法,那么进行这些检查会使代码变得笨拙.因此,如果可能的话,请在java中提出一些优雅的方法来实现此功能.

我面临的问题是future.cancel实际上不会取消任务.相反,它只是发送一个InterruptedException执行任务,任务的责任是标记自己完成并释放线程.

所以我所做的是,每当在执行中的任何地方抛出异常时,我必须放下下面的代码块,这显然看起来不太好!

if(e instanceof InterruptedException) {
                    throw e;
                }
Run Code Online (Sandbox Code Playgroud)

那么,如何在以下代码片段中实现此功能:

public class MonitoringInParallelExp {

        public static void main(String[] args) throws InterruptedException {
            MyClass1 myClass1 = new MyClass1();
            ExecutorService service = Executors.newFixedThreadPool(1);
            Future<String> future1 = service.submit(myClass1);
            Thread.sleep(2000);
            System.out.println("calling cancel in Main");
            future1.cancel(true);
            System.out.println("finally called cancel in Main");
            service.shutdown();
        }
    }

    class MyClass1 implements Callable<String> {
        @Override
        public String call() throws Exception {
            try{
                MyClass2 myClass2 = new MyClass2();
                myClass2.method2();
            } catch (Exception e){
                if(e instanceof InterruptedException) {
                    System.out.println("call:"+"e instanceof InterruptedException="+"true");
                    throw e;
                }
                System.out.println("Got exception in method1. " + e);
            }
            System.out.println("returning Myclass1.method1.exit");
            return "Myclass1.method1.exit";
        }
    }

    class MyClass2 {
        public void method2() throws Exception{
            try{
                MyClass3 myClass3 = new MyClass3();
                myClass3.method3();
            } catch (Exception e){
                if(e instanceof InterruptedException) {
                    System.out.println("method2:"+"e instanceof InterruptedException="+"true");
                    throw e;
                }
                System.out.println("Got exception in method2. " + e);

                // in case the exception isn't InterruptedExceptionm, do some work here
            }
        }
    }

    class MyClass3 {
        public void method3() throws Exception{
            try{
                Thread.sleep(10000);
            } catch (Exception e){
                if(e instanceof InterruptedException) {
                    System.out.println("method3:"+"e instanceof InterruptedException="+"true");
                    throw e;
                }
                System.out.println("Got exception in method3. " + e);
                throw new MyException();
            }
        }
    }

    class MyException extends Exception {

    }
Run Code Online (Sandbox Code Playgroud)

Mur*_*göz 5

打断Callable不打断都无所谓,因为那时已经太晚了

try{
  MyClass2 myClass2 = new MyClass2();
  myClass2.method2();
} catch (Exception e){
Run Code Online (Sandbox Code Playgroud)

您对通话future1.cancel(true);后,Thread.sleep(2000)实际上并没有取消正在进行的任务(在这种情况下,您的method2通话),它只是意味着它要它开始之前已被取消。

文档指出 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)

尝试取消此任务的执行。如果任务已完成、已被取消或由于其他原因无法取消,则此尝试将失败。如果成功,并且在调用取消时此任务尚未启动,则不应运行此任务。如果任务已经开始,则 mayInterruptIfRunning 参数确定是否应该中断执行此任务的线程以尝试停止任务。

如果您想取消正在进行的任务,您需要使用volatile boolean标志或类似的东西。