gpt4 book ai didi

java - 为什么 ExecutorService 从类加载器线程启动时不处理提交的任务?

转载 作者:行者123 更新时间:2023-12-01 19:44:15 25 4
gpt4 key购买 nike

我有一个类Singleton(本示例进行了简化)

public class Singleton {
private final static Lock METHOD_1_LOCK = new ReentrantLock();
private final static Lock METHOD_2_LOCK = new ReentrantLock();
static {
try {
init();
}catch(InterruptedException ex) {
throw new ExceptionInInitializerError(ex);
}
}

public static void init() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
method1();
});
executorService.submit(() -> {
method2();
});
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}

public static List<String> method1() {
METHOD_1_LOCK.lock();
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1");
return Stream.of("b").collect(Collectors.toList());
}finally {
METHOD_1_LOCK.unlock();
}
}

public static List<String> method2() {
METHOD_2_LOCK.lock();
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("2");
return Stream.of("a").collect(Collectors.toList());
}finally {
METHOD_2_LOCK.unlock();
}
}

private Singleton() {
}
}

我想通过在单独的线程上调用Class.forName来预初始化:

public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Class.forName(Singleton.class.getName());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
// working alternative:
// try {
// Singleton.init();
// }catch(InterruptedException ex) {
// ex.printStackTrace();
// }
});
thread.start();
thread.join();
}

此构造永远不会从 ExecutorService.awaitTermination 返回(预计会在 1 秒后返回)。

如果我通过注释(并注释掉其他代码)切换到标记为“工作替代方案”的代码,并注释掉 Singleton 中的 static block ,则代码是按预期执行(method1method2 被调用,并根据输出以相反的顺序返回)。

由于“可行的替代方案”可以防止该问题,并且我可以忍受它,因此我正在寻找对此行为的解释。

我使用 Class.forName 而不是 Singleton.init 的目的是能够向 Singleton 添加更多静态初始化任务,而无需需要考虑它们是否被预初始化例程覆盖。我同意整个设置并不理想。

最佳答案

你正朝着错误的方向前进。首先,在类初始化时切勿进行大量计算。在类初始化完成之前,类方法的调用受到限制。这个想法不是向类方法显示尚未初始化的变量。只有直接从静态初始化程序调用的方法才能执行,否则它们将被阻塞。在您的情况下,并行任务中对 method1method2 的调用将被阻止。

一般来说,尽可能避免使用静态变量。相反,创建对象的实例。对于给定的情况,创建 Singleton 类的实例,并将所有变量从静态字段转换为实例字段。

最后,不要运行线程只是为了调用

  thread.start();
thread.join();

最好直接调用作为Runnable传递到线程的方法。

关于java - 为什么 ExecutorService 从类加载器线程启动时不处理提交的任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54060398/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com