JEE 7 WildFly环境下如何实现调度器无阻塞异步执行任务
在JEE 7 WildFly中实现调度器的“即发即弃”异步任务
你遇到的问题很典型——在JEE托管容器里不能随便new Thread,得用容器提供的异步机制才行。你的示例代码里犯了个关键错误:直接new Worker实例,这样容器根本不会管理这个对象,@Asynchronous注解自然也不会生效,还违反了JEE规范。
下面给你一套完全符合容器托管要求的正确实现方案:
第一步:修正Worker EJB
无状态EJB(@Stateless)不能有带参数的构造器,容器需要通过默认构造器创建实例并池化。我们把参数通过方法传递进去,同时确保@Asynchronous注解正确作用在方法上:
@Stateless public class Worker { private static final Logger LOGGER = LogManager.getLogger(Worker.class); // 用@Asynchronous标记方法为异步执行 @Asynchronous public void doSomethingWithoutBlocking(int taskNumber) { for(long i = 0; i < 10000000000L; i++) { if(i % 1000000000 == 0) { LOGGER.info("{}. Worker: i = {}", taskNumber, i); } } } }
第二步:调整调度器,正确注入并调用异步方法
调度器里不能new Worker,要通过@EJB注解让容器注入管理好的EJB实例。调用异步方法时,容器会自动从线程池分配后台线程执行,调度器的方法会立即返回,完全不会阻塞:
@Startup @Singleton public class MyScheduler { private static final Logger LOGGER = LogManager.getLogger(MyScheduler.class); private int counter = 0; // 让容器注入Worker EJB实例 @EJB private Worker worker; @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void atSchedule() { int currentTask = ++counter; LOGGER.info("{}. scheduler call - every five secs.", currentTask); // 调用异步方法,容器会立即返回,任务在后台执行 worker.doSomethingWithoutBlocking(currentTask); LOGGER.info("Scheduler done."); } }
关键知识点说明
- 为什么不能new EJB?:JEE容器负责EJB的生命周期、线程池管理、事务控制等,直接new出来的只是普通Java对象,容器不会处理它的异步注解,也不会纳入资源管理,这是容器规范明确禁止的操作。
- @Asynchronous的作用:标记方法后,容器会把方法执行提交到专门的异步线程池,调用方(调度器)会立刻继续执行后续代码,完美实现“即发即弃”。
- 无状态Bean的优势:无状态EJB是池化的,适合这种无状态的异步任务,容器可以复用实例,避免频繁创建对象的开销。
如果需要更精细的控制(比如获取异步任务的执行结果),可以让异步方法返回Future<Void>,不过你的“即发即弃”需求用上面的方案就足够了。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

