使用Callable Future的简单程序永远不会终止

时间:2018-03-12 17:30:04

标签: concurrency future callable

我正在玩Callable和Future,偶然发现了一个问题。

即使IDE允许运行5秒钟,这段代码永远不会终止并超时,并且代码不需要超过3秒(它会超出时间限制错误):https://ideone.com/NcL0YV

/* package whatever; // don't place package name! */

import java.util.*;
import java.util.concurrent.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Ideone obj = new Ideone();
        Future<Integer> res = obj.doCallable();
        System.out.println(res.get());
    }
    public Future<Integer> calculate(Integer input) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        return executor.submit(() -> {
            long start = System.currentTimeMillis();
            Thread.sleep(2000);
            System.out.println("Sleep time in ms = "+(System.currentTimeMillis()-start));
            return input * input;
        });
    }
    public Future<Integer> doCallable() {
        int value = 99;
        try {
            Callable<Future> callable = () -> calculate(value);
            Future<Integer> future = callable.call();
            return future;
        } catch (final Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

这是一段类似的代码终止,因为我添加了&#34; System.exit(0)&#34; (这不可取):https://ideone.com/HDvl7y

/* package whatever; // don't place package name! */

import java.util.*;
import java.util.concurrent.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Ideone obj = new Ideone();
        Future<Integer> res = obj.doCallable();
        System.out.println(res.get());
        System.exit(0);
    }
    public Future<Integer> calculate(Integer input) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        return executor.submit(() -> {
            long start = System.currentTimeMillis();
            Thread.sleep(2000);
            System.out.println("Sleep time in ms = "+(System.currentTimeMillis()-start));
            return input * input;
        });
    }
    public Future<Integer> doCallable() {
        int value = 99;
        try {
            Callable<Future> callable = () -> calculate(value);
            Future<Integer> future = callable.call();
            return future;
        } catch (final Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

请帮助我理解为什么我们需要System.exit(0)或shutdown(),即使可调用任务完成(future.get()调用是阻塞调用)。

修改 由于下面的代码片段,我做了以上所有解决我的应用程序中不断增加的线程的主要问题。我不确定如何在一定的超时后自动完成这个未来而不涉及主线程(立即退出)。

@Override
public void publish(@NonNull final String message,
                    @NonNull final String topicArn) throws PublishingException {
    if (!publishAsync(message, topicArn)) {
        throw new PublishingException("Publish attempt failed for the message:"
                + message);
    }
}

private boolean publishAsync(final String message,
                             final String topicArn) {
    Callable<Future> publishCallable = () -> snsClient.publishAsync(topicArn, message);
    try {
        Future<PublishResult> result = publishCallable.call();
        log.debug("Asynchronously published message {} to SNS topic {}.", message, topicArn);
        return !result.isDone() || result.get().getMessageId() != null;
    } catch (final Exception e) {
        return false;
    }
}

1 个答案:

答案 0 :(得分:0)

空隙shutdown()方法

启动有序关闭,其中先前提交的任务已执行,但不会接受任何新任务。如果已经关闭,调用没有额外的效果。

此方法不会等待先前提交的任务完成执行。使用awaitTermination来做到这一点。