我正在使用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
监视线程无法检测到任何死锁。为什么它表现怪异?
您的Cache
类的静态初始值设定项未完成-它正在等待future.get()
的完成。您可以删除static
初始化程序,然后直接从Cache.initialize()
或其他地方调用您的方法– main()
,但是无论如何执行该操作都会被类似地阻塞。
我建议您创建一个单独的线程来调用initialize()
,从而避免阻塞行为,如下所示:
new Runnable() {
@Override
public void run() {
initialize();
}
}.run();
这似乎是预期的行为。这是经典的类初始化死锁。
使用依赖于类的静态初始化完成的Runnable启动新线程。继而,由于
future.get()
方法调用,该类正在等待Runnable完成。静态初始化正在等待线程完成,而线程正在等待静态初始化完成。
[JLS:: Class initialiization提供有关类初始化过程的详细信息。
我想知道为什么jconsole
无法检测到死锁