Java Glassfish 4-使用并发API创建托管线程
我正在尝试使用新的并发API来注入一个并使用它 下面是我所说的一个例子:Java Glassfish 4-使用并发API创建托管线程,java,multithreading,glassfish,java-ee-7,Java,Multithreading,Glassfish,Java Ee 7,我正在尝试使用新的并发API来注入一个并使用它 下面是我所说的一个例子: @Singleton @Startup public class Demo { @Resource(name="concurrent/__DefaultManagedThreadFactory") ManagedThreadFactory threadFactory; @PostConstruct public void startup() { threadFactory.newT
@Singleton
@Startup
public class Demo {
@Resource(name="concurrent/__DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;
@PostConstruct
public void startup() {
threadFactory.newThread(
new Runnable() {
@Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
我正在Eclipse中使用Glassfish插件进行开发。在进行更改后重新发布时,我总是在服务器日志中看到这一行。每次调用start()时,它都会出现一次:
它实际上并没有抛出一个非法状态异常,只是报告一个被抛出(并捕获)到玻璃鱼里面。应用程序正常部署,但没有线程启动。如果我随后重新发布并再次发布,那么“错误”将消失,线程将按预期启动
当我尝试将应用程序部署到“真实”的Glassfish设置(没有Eclipse)时,它总是报告部署成功,并且日志中不包含“错误”。但它仍然不会启动线程(即使是重复部署)
我是否正确使用了并发API?可能是配置问题吗?作为记录,如果改用ManagedExcecutorService,我会得到相同的行为
为了记录在案,几个月前在这里有人问过这个问题:,但它并没有得到真正的回答,而且我还没有名声去做任何事情,只是再问一次。对不起
更新:由works提供。非常感谢。我对该解决方案进行了一些重构,试图将解决方案代码与原始应用程序逻辑隔离开来:
@Singleton
@Startup
public class Demo {
@Resource(name="java:comp/DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;
@EJB private ConcurrencyInitializer concurrencyInitializer;
@EJB private Demo self;
@PostConstruct
public void startup() {
self.startThread();
}
@Asynchronous
public void startThread() {
//This line applies the workaround
concurrencyInitializer.init();
//Everything beyond this point is my original application logic
threadFactory.newThread(
new Runnable() {
@Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
/**
*一个实用类,用于绕过Glassfish中的一个bug,该bug允许
*并发资源(ManagedThreadFactory、ManagedExecutorService等)
*在准备使用前进行注射。
*
*从Per Axel Felth的溶液中提取:https://stackoverflow.com/questions/23900826/glassfish-4-using-concurrency-api-to-create-managed-threads
*/
@独生子女
公共类并发初始化器{
/**
*尝试执行之前要等待的毫秒数
*/
公共静态最终长重试延迟=500L;
/**
*失败前进行的最大并发尝试次数
*/
公共静态最终整数最大重试次数=20次;
/**
*反复尝试向注入的ManagedExecutorService提交可运行任务
*触发并发资源的准备。
*
*@return true如果成功(并发资源现在可以使用),
*如果超时,则为false
*/
公共布尔init(){
最终原子布尔完成=新原子布尔(false);
int i=0;
试一试{
而(!done.get()&&i++
我怀疑您的ManagedThreadFactory没有正确注入,因此“演示”组件没有启动
JavaEE7规范要求在JNDI中提供名为“Java:comp/DefaultManagedThreadFactory”的托管线程工厂,因此请尝试将@Resource更改为
@Resource(name="java:comp/DefaultManagedThreadFactory")
我不熟悉Glassfish(我是一个野蝇类的家伙),但你可能在任何JNDI树显示中都看不到这个参考。它可能在内部链接到“concurrent/_DefaultManagedThreadFactory”(顺便说一句,它不是资源名称)
如果失败,你也可以尝试
@Resource(lookup="concurrent/__DefaultManagedThreadFactory")
它与一种玻璃鱼虫有关。不久前,我自己也遇到了同样的错误,并建立了一个解决方案。问题是,线程工厂是注入好的,但如果你使用它“太早”,你将以一个非法状态异常结束 下面列出了我的解决方案代码。它使用注入的executor服务来检测何时加载应用程序以及并发UTIL是否可用,然后执行方法
init
中的实际启动逻辑
@Singleton
@Startup
public class Demo {
@Resource(name = "concurrent/__DefaultManagedThreadFactory")
ManagedThreadFactory threadFactory;
@Resource
ManagedExecutorService executorService;
@EJB
Demo me;
@PostConstruct
public void startup() {
me.waitAndInitialize();
}
@Asynchronous
public Future<?> waitAndInitialize() {
try {
final AtomicInteger done = new AtomicInteger(0);
int i = 0;
while (done.intValue() == 0 && i < 20) {
System.out.println("Is executor service up?");
i++;
executorService.submit(
new Runnable() {
@Override
public void run() {
int incrementAndGet = done.incrementAndGet();
System.out.println("Run by executorservice");
}
});
Thread.sleep(500);
}
if (done.intValue() == 0) {
Logger.getAnonymousLogger().severe("Waited a long time for the ExecutorService do become ready, but it never did. Will not initialize!");
} else {
init();
}
} catch (Exception e) {
Logger.getAnonymousLogger().log(Level.SEVERE, "Exception in waitAndInitialize: " + e.getMessage(), e);
}
return new AsyncResult<>(null);
}
private void init() {
threadFactory.newThread(
new Runnable() {
@Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
@Singleton
@启动
公开课演示{
@资源(name=“concurrent/\uuu DefaultManagedThreadFactory”)
ManagedThreadFactory线程工厂;
@资源
ManagedExecutorService执行器服务;
@EJB
演示我;
@施工后
公共无效启动(){
me.waitAndInitialize();
}
@异步的
公共未来等待和初始化(){
试一试{
最终AtomicInteger完成=新的AtomicInteger(0);
int i=0;
while(done.intValue()==0&&i<20){
System.out.println(“执行器服务启动了吗?”);
i++;
执行器服务。提交(
新的Runnable(){
@凌驾
公开募捐{
int incrementAndGet=done.incrementAndGet();
System.out.println(“由executorservice运行”);
}
});
睡眠(500);
}
if(done.intValue()==0){
Logger.getAnonymousLogger().severy(“等待ExecutorService准备好很长时间,但它从未准备好。将不会初始化!”);
}否则{
init();
}
}捕获(例外e){
Logger.getAnonymousLogger().log(Level.severy,“waitAndInitialize中的异常:”+e.getMessage(),e);
}
返回新的异步结果(空);
}
私有void init(){
threadFactory.newThread(
新的Runnable(){
@凌驾
公开募捐{
System.out.println(“做点什么”);
}
}
).start();
}
}
谢谢您的回复。我更改了注入的@Resource的名称,但仍然得到相同的行为。但我认为你是对的,看起来ManagedThreadFactory
@Resource(lookup="concurrent/__DefaultManagedThreadFactory")
@Singleton
@Startup
public class Demo {
@Resource(name = "concurrent/__DefaultManagedThreadFactory")
ManagedThreadFactory threadFactory;
@Resource
ManagedExecutorService executorService;
@EJB
Demo me;
@PostConstruct
public void startup() {
me.waitAndInitialize();
}
@Asynchronous
public Future<?> waitAndInitialize() {
try {
final AtomicInteger done = new AtomicInteger(0);
int i = 0;
while (done.intValue() == 0 && i < 20) {
System.out.println("Is executor service up?");
i++;
executorService.submit(
new Runnable() {
@Override
public void run() {
int incrementAndGet = done.incrementAndGet();
System.out.println("Run by executorservice");
}
});
Thread.sleep(500);
}
if (done.intValue() == 0) {
Logger.getAnonymousLogger().severe("Waited a long time for the ExecutorService do become ready, but it never did. Will not initialize!");
} else {
init();
}
} catch (Exception e) {
Logger.getAnonymousLogger().log(Level.SEVERE, "Exception in waitAndInitialize: " + e.getMessage(), e);
}
return new AsyncResult<>(null);
}
private void init() {
threadFactory.newThread(
new Runnable() {
@Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}