我正在尝试使用新的并发API注入ManagedThreadFactory并按每个Oracle教程使用它。
下面是我要说的一个例子:
@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插件进行开发。更改后重新发布时,总是会在服务器日志中得到这一行。我们发出的每个呼叫似乎只有一次:
SEVERE: java.lang.IllegalStateException: Module (my application) is disabled它实际上并没有抛出一个IllegalStateException,只是报告了一个在玻璃鱼体内被抛出(并被捕获)。应用程序正常部署,但没有启动任何线程。如果我随后重新发布并第二次发布,“错误”就会消失,线程将按预期的方式启动。
当我尝试将应用程序部署到“真正的”Glassfish设置(没有Eclipse)时,它总是报告成功的部署,并且日志中不包含"error“。但是它仍然没有启动线程(即使是重复部署)。
我是否正确地使用了并发API?会不会是配置问题?为了记录在案,如果我使用ManagedExcecutorService,我会得到相同的行为。
作为记录,这个问题是几个月前在这里被问到的:https://stackoverflow.com/questions/20446682/can-i-start-a-managedthread-in-a-singleton-enterprise-java-bean,但它没有得到真正的回答,而且我除了再问一次外,还没有什么可做的。抱歉的!
更新:这个答案 by 佩尔-阿克塞尔·费尔思 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();
}
}/**
* A utility class used to get around a bug in Glassfish that allows
* Concurrency resources (ManagedThreadFactory, ManagedExecutorService, etc)
* to be injected before they are ready to be used.
*
* Derived from solution by Per-Axel Felth in: https://stackoverflow.com/questions/23900826/glassfish-4-using-concurrency-api-to-create-managed-threads
*/
@Singleton
public class ConcurrencyInitializer {
/**
* The number of milliseconds to wait before try to
*/
public static final long RETRY_DELAY = 500L;
/**
* The maximum number of concurrency attempts to make before failing
*/
public static final int MAX_RETRIES = 20;
/**
* Repeatedly attempts to submit a Runnable task to an injected ManagedExecutorService
* to trigger the readying of the Concurrency resources.
*
* @return true if successful (Concurrency resources are now ready for use),
* false if timed out instead
*/
public boolean init() {
final AtomicBoolean done = new AtomicBoolean(false);
int i = 0;
try {
while (!done.get() && i++ < MAX_RETRIES) {
executorService.submit(new Runnable() {
@Override
public void run() {
done.set(true);
}
});
Thread.sleep(RETRY_DELAY);
}
} catch(InterruptedException e) {
//Do nothing.
}
return done.get();
}
}发布于 2015-02-06 06:45:22
与一只玻璃鱼虫有关。一段时间前,我自己也遇到了同样的问题,并建立了一个解决办法。问题是,线程工厂的注入是正常的,但是如果您使用它“太早”,您将得到一个IllegalStateException。
下面列出了我的解决方案代码。它使用注入的执行器服务来检测何时加载了app,何时可用并发工具,然后在方法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();
}
}发布于 2014-05-28 05:18:34
我怀疑您的ManagedThreadFactory没有被正确注入,所以“演示”组件没有启动。
Java 7规范要求在JNDI中使用名为"java:comp/DefaultManagedThreadFactory“的托管线程工厂,因此尝试将@Resource更改为
@Resource(name="java:comp/DefaultManagedThreadFactory")我不熟悉Glassfish (我是一个WildFly类型的家伙),但是您可能在任何JNDI树显示中都看不到这个引用。它可以在内部链接到“并发/_DefaultManagedThreadFactory”(它不是资源名称btw)。
如果做不到,你也可以试试
@Resource(lookup="concurrent/__DefaultManagedThreadFactory")https://stackoverflow.com/questions/23900826
复制相似问题