【问题标题】:Unable to execute task using ExecutorService in static workflow/block无法在静态工作流/块中使用 ExecutorService 执行任务
【发布时间】:2019-12-20 18:31:20
【问题描述】:

我正在开发一个使用static 工作流加载一次性缓存的模块。缓存加载通常需要大约一个小时。为了提高性能,我正在考虑使用线程池并行运行这些任务。这是示例代码。

应用启动类:

public class AppStart {
    public static void main(String[] args) {
        Cache.isValid();  // this will trigger the static workflow
        // ...
    }
}

缓存加载器类:

public class Cache {

    static {
        System.out.println("Static block initialization started!");
        initialize();
        System.out.println("Static block initialization finished!");
    }

    public static void initialize( ) {
        System.out.println("initialize() started!");
        ExecutorService executorService = Executors.newSingleThreadExecutor(); // will replace with fixedThreadPool
        Future<String> future = executorService.submit(() -> "Hello world!");
        System.out.println("Retrieve the result of the future");
        String result = null;
        try {
            result = future.get();
            System.out.println(result);
        } catch( InterruptedException e ) {
            e.printStackTrace();
        } catch( ExecutionException e ) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    public static boolean isValid( ) {
        return true;
    }
}

但是,在上述情况下,阻塞操作future.get 将被永远阻塞,即使它只做一个返回字符串的微不足道的任务。

我也尝试过使用ForkJoinPool,但没有运气。

我使用jconsole 监控线程无法检测到任何死锁。为什么它的行为很奇怪?

【问题讨论】:

  • 我想看看它为什么失败的解释。但是无论如何阻止类的初始化都是一个坏主意。移除静态块,并在 main() 中显式调用 initialize()。

标签: java future executorservice forkjoinpool


【解决方案1】:

Cache 类的静态初始化程序未完成 - 它正在等待 future.get() 完成。您可以删除 static 初始化程序并直接从 main() 或其他地方调用您的方法 - Cache.initialize(),但无论线程做什么都会被类似地阻塞。

我建议你创建一个单独的线程来调用initialize(),从而避免阻塞行为,像这样:

new Runnable() {
    @Override
    public void run() {
        initialize();
    }
}.run();

【讨论】:

  • 我知道它在等待future.get() 但是为什么等待这么久,提交的任务很轻量级。
【解决方案2】:

这似乎是预期的行为。这是一个经典的类初始化死锁。

使用依赖于类的静态初始化完成的 Runnable 启动一个新线程。反过来,由于future.get() 方法调用,该类正在等待 Runnable 完成。 静态初始化等待线程完成,线程等待静态初始化完成。

JLS:: Class initialiization 提供了类初始化过程的详细信息。

不知道为什么jconsole 检测不到死锁

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 2012-01-31
    相关资源
    最近更新 更多