有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java未来。回调捕获InterruptedException时获取挂起

此代码挂起。我知道我称之为未来。未执行的将来的get(),但我希望在将来看到CancellationException或InterruptedException或其他一些异常。get()方法。我错了吗

public class ExecutorTest {
    static ExecutorService executorService = Executors.newFixedThreadPool(1);
    public static void main(String[] args) throws Exception {
        List<Future> futures = new ArrayList<Future>();
        for (int i = 0; i < 10; i++) {
            Future<Object> future = executorService.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    System.out.println("Start task");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Finish task");
                    return "anything";
                }
            });
            futures.add(future);
        }

        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                    System.out.println("Shutdown Now");
                    executorService.shutdownNow();
                } catch (InterruptedException e) {
                    System.out.println("Interrupted Exception during shutdown");
                }
            }
        }.start();

        for(Future f : futures) {
            System.out.println("-------------------------");
            System.out.println("before sleep");
            Thread.sleep(3000);
            System.out.println("after sleep...");
            try {
                f.get();
            } catch (Exception ex) {
                System.out.println("exception during future.get");
            }
            System.out.println("after get!");
        }

    }
}

这是我的输出

Start task
-------------------------
before sleep
after sleep...
Finish task
after get!
-------------------------
Start task
before sleep
after sleep...
Finish task
Start task
after get!
-------------------------
before sleep
after sleep...
Finish task
Start task
after get!
-------------------------
before sleep
Shutdown Now
Finish task
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at ru.pp.ExecutorTest$1.call(ExecutorTest.java:28)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
after sleep...
after get!
-------------------------
before sleep
after sleep...

Java8,Intellij

如果我替换

System.out.println("Start task");
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

用这个

System.out.println("Start task");
Thread.sleep(3000);

那它就挂不住了

我很沮丧


共 (2) 个答案

  1. # 1 楼答案

    当线程1调用FutureTask#get时,就会调用线程1#wait。现在要继续线程1,应该有人通知它。仅当FutureTask终止时(在FutureTask#setFutureTask#setExceptionFutureTask#cancel上)才会调用通知。但是在我的例子中,FutureTask从来没有启动过,因为现在关机了(FutureTask处于新状态)。因此它从未被终止,也从未调用过线程1#通知。 为了解决这个问题,我没有从\shutdownow启动期货,也没有为他们调用FutureTask\get

    PS:老实说,未来任务使用太阳。杂项。不安全的#停车#未解析方法,而不是等待并通知

  2. # 2 楼答案

    当您调用shutdownNow时,ExecutorService将删除任何已计划但尚未运行的任务,并将它们作为List<Runnable>返回给您。这些任务有一个对应的Future,您已经有了对它的引用。由于这些任务从未运行过,因此它们从未产生结果,即从未完成。因此,这些任务的Future#get()将永远不会返回

    如果愿意,可以返回并运行这些任务

    executorService.shutdownNow().forEach(r -> r.run());
    

    您将看到所有Future#get()调用返回

    如果知道任务已完成/取消,则可能只应调用Future#get()。或者,给它一个超时