Jakarta ee Liberty在使用ManagedExecutorService时无限期挂起

Jakarta ee Liberty在使用ManagedExecutorService时无限期挂起,jakarta-ee,websphere-liberty,java-ee-7,Jakarta Ee,Websphere Liberty,Java Ee 7,我正在尝试将遗留应用程序迁移到当前的jee 7标准 在应用程序部署/引导过程中,我们通过启动servlet初始化一些缓存。在部署过程中,其他应用程序组件很少使用缓存。这些在遗留应用程序中按顺序初始化。我试图引入多线程来并行初始化所有缓存。因此,我正在使用ManagedExecutorService并提交任务。提交任务后,部署将持续一段时间并无限期停止。下面是我的代码 for(Cacheable cacheable: cacheableApps.values()) { mes.submit

我正在尝试将遗留应用程序迁移到当前的jee 7标准

在应用程序部署/引导过程中,我们通过启动servlet初始化一些缓存。在部署过程中,其他应用程序组件很少使用缓存。这些在遗留应用程序中按顺序初始化。我试图引入多线程来并行初始化所有缓存。因此,我正在使用ManagedExecutorService并提交任务。提交任务后,部署将持续一段时间并无限期停止。下面是我的代码

for(Cacheable cacheable: cacheableApps.values()) {
    mes.submit(new Runnable(){
        public void run() {
            cacheable.initialize();
        }
    });
}
我还尝试使用ManagedExecutorService.execute(Runnable)和ManagedExecutorService.submit(Callable),但运气不佳

此外,我尝试调用ManagedExecutorService.invokeAll(Collection)和Future.get(),但此时服务器无限期挂起

然后,我用ManagedThreadFactory替换ManagedExecutorService,线程开始初始化,部署在使用缓存的其他应用程序组件中使用NPE完成。这是因为缓存在部署结束时正在初始化

其思想是用启动单例ejb替换启动servlet,在多个线程中初始化缓存,并停止部署过程,直到所有线程返回,这样就不会抛出NPE,部署也会顺利完成

在使用ManagedThreadFactory时,我尝试停止部署,如下所示

for(Cacheable cacheable: cacheableApps.values()) {
    RunnableTask task =new RunnableTask(cacheable);
    mtf.newThread(task).start();
    tasks.add(task);
}
int count = 0;
while(count!=tasks.size()) {
    count = 0;
    for(Task task: tasks) {
        if(task.isDone()) {
            count++;
        }
    }
}

public class RunnableTask implements Runnable {
    private boolean done;
    public(Cacheable cacheable) {
        this.cacheable = cacheable;
    }
    public void run() {
        cacheable.initialize();
        done = true;
    }
    public boolean isDone() {
        return done;
    }
}
但这段代码也会无限期地挂起服务器。因为线程在while循环中执行时尚未启动。线程仅在部署结束时启动。所以上面的代码是无效的

为了调试这个问题,我创建了一个虚拟的restful web服务,并添加了以下代码

Future<String> future = mes.submit(new Callable<String>() {
    public String call() throws Exception {
        Cacheable.STUDENT.getApp().initialize();
        return "successful";
    }
});

return future.get();
Future-Future=mes.submit(新的可调用(){
公共字符串调用()引发异常{
Cacheable.STUDENT.getApp().initialize();
返回“成功”;
}
});
返回future.get();
这初始化了缓存,web服务的响应为“成功”

然后,我将确切的代码复制到启动servlet,在执行future.get()时,部署再次挂起


我想知道缓存代码是否有问题,删除了调用并简单地返回“successful”。调用future.get()时,部署再次挂起。我想我发现了问题所在。相同的代码在ejb中运行良好,而不是在启动servlet或servlet侦听器中


此外,我还发现,当发送http请求时,相同的代码在常规servlet或restful web服务中工作正常。这是liberty中的一个bug,还是ee规范不允许servlet容器在初始化/部署/引导过程中访问并发特性?

听起来可能是个bug。您应该收集服务器线程的转储,以便进一步诊断挂起。服务器挂起时,运行以下命令

server dump <your-server-name>
在zip文件中,将有一个子文件夹,例如dump_17.04.04_08.21.56,其中包含一个名为threadinfointerspector.txt的文本文件


此文件包含服务器中所有活动线程的堆栈。他们中的许多人可能是空闲的。张贴所有正在工作的堆栈(挂起),以便进一步分析可能的错误。

我想我发现了问题所在。相同的代码在ejb中运行良好,而不是在启动servlet或servlet侦听器中。我发现,当发送http请求时,相同的代码在常规servlet或restful web服务中运行良好。这是liberty中的一个bug,还是ee规范不允许servlet容器在初始化/部署/引导期间访问并发特性?然后将此作为答案发布,以便其他人可以使用它。如果您只需要一个线程转储,
server javadump
命令可能更方便。
wlp/usr/servers/your-server-name/your-server-name.dump-17.04.04_08.21.56.zip