EJB 3.0规范不允许无状态会话bean的业务方法创建新线程。这是为什么?创建仅执行原始计算并且从不调用应用服务器的其他工作线程有什么问题?
说,我的会话bean实现了一个允许用户上传图像的服务,而业务方法对这些图像进行了cpu密集型图像处理。那么即使机器有8个或更多核心,它也只能使用一个cpu核心来完成这项工作?如果我利用第三方图像处理库,在内部创建工作线程,我也会违反EJB规范,即使该库和这些线程根本与EJB容器无关。这似乎不对。
如果我忽略EJB规则并仍然创建一些工作线程来执行cpu密集处理,会发生什么?当然这些线程永远不会触及任何app服务器对象,bean线程会在返回之前加入它们。仍然可能发生一些不好的事情?
答案 0 :(得分:18)
EJB 3.0规范不允许无状态会话bean的业务方法创建新线程。那是为什么?
简短版本:不允许从EJB管理线程,因为它会损害资源管理,事务管理,安全性(技术原因),也因为这是EJB模型不想推广的内容(哲学原因)。
EJB规范如下:
21.1.2编程限制
...
- 企业bean不得尝试管理线程。企业bean不得尝试启动,停止,暂停或恢复线程,或更改线程的优先级或名称。企业bean不得尝试管理线程组。
这些函数是为EJB容器保留的。允许企业bean管理线程会降低容器正确管理运行时环境的能力。
(...)如果我利用第三方图像处理库,在内部创建工作线程,我也会违反EJB规范,即使该库和这些线程根本与EJB容器无关。这似乎不对。
我能说什么,如果你不喜欢这样,就不要使用EJB。
如果我忽略EJB规则并仍然创建一些工作线程来执行cpu密集处理,会发生什么?当然这些线程永远不会触及任何app服务器对象,bean线程会在返回之前加入它们。仍然可能发生一些不好的事情?
这些线程是否正在触及app服务器对象并不重要。规则是规则,你不想跟随它们,你是独立的,行为是未定义的。一些容器可能更宽松并允许它,其他一些不会,你的应用程序将无法移植等等。但它仍然是明确禁止的。
如果要以标准方式“生成”线程,请使用WorkManager API,或使用JMS。
答案 1 :(得分:1)
在我的简化理解中,它就像经营公司一样。你是老板(集装箱),而且有一个员工突然只是在没有任何通知的情况下雇佣了100个人(豆子)。
但你仍然可以使用@Asynchronous注释轻松进行多线程处理(还有其他方法)。
@Stateless
public class Employee {
@Asynchronous
public Future<Void> work(Project projectThatTakeTooLong) {
// work work work
return new AsyncResult<Void>(null);
}
}
@Stateless
public class Boss {
@Inject
private Employee randomStatelessEmployee;
public void giveWork() {
Future<Void> result1 = randomStatelessEmployee.work(new Project());
Future<Void> result2 = randomStatelessEmployee.work(new Project());
Future<Void> result3 = randomStatelessEmployee.work(new Project());
result1.get();
result2.get();
result3.get();
}
}
这里还有一个更好的例子: Jboss Java EE container and an ExecutorService
答案 2 :(得分:1)
一种解决方法:
import java.util.concurrent.Executor;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;
@Stateless
public class TransactionalExecutor implements Executor {
@Override @Asynchronous
public void execute(Runnable command) {
command.run();
}
}
现在您可以使用TransactionalExecutor作为执行者:
@Stateless
public class SlowService {
@Inject
Executor command;
public void invoke(){
Runnable command = new Runnable() {
@Override
public void run() {
// heavy task
}
};
command.execute(command);
}
}
答案 3 :(得分:0)
已知限制不在J2EE应用程序中使用线程。 应用程序服务器应该负责程序的并行执行
是的,您可以忽略EJB规则,但可以面对极不可预测的行为。