[英]Jboss Java EE container and an ExecutorService
我有一個獨立的Java應用程序,它使用ExecutorService並行處理大量作業
ExecutorService es = Executors.newFixedThreadPool(10);
我現在想在EJB bean中重用相同的解決方案但不確定如何正確初始化ThreadPool,因為我通常會讓Java EE容器控制所有線程資源。 我可以使用相同的代碼,還是有另一種正確的方法來獲取Jboss托管線程池?
在EJB中執行此操作的正確方法是使用ManagedExecutorService,它是Concurrency Utils API(Java EE7)的一部分。 您不應該使用屬於企業代碼中java.util.concurrent的任何ExecutorService。
通過使用ManagedExecutorService,您的新線程將由容器創建和管理。
下面的例子是從我的網站采取了這里 。
要使用ManagedExecutorService創建新線程,首先要創建一個實現Callable的任務對象。 在call()方法中,我們將定義我們想要在單獨的線程中執行的工作。
public class ReportTask implements Callable<Report> {
Logger logger = Logger.getLogger(getClass().getSimpleName());
public Report call() {
try {
Thread.sleep(3000);
catch (InterruptedException e) {
logger.log(Level.SEVERE, "Thread interrupted", e);
}
return new Report();
}
}
然后我們需要通過將任務傳遞給ManagedExecutorService的submit()方法來調用該任務。
@Stateless
public class ReportBean {
@Resource
private ManagedExecutorService executorService;
public void runReports() {
ReportTask reportTask = new ReportTask();
Future<Report> future = executorService.submit(reportTask);
}
}
強制警告:不鼓勵在Java EE應用服務器(甚至Tomcat)中創建自己的線程,因為它可能是一個巨大的性能問題,並且在大多數情況下會阻止容器功能(如JNDI)工作。 新線程將不知道它們屬於哪個應用程序,不會設置Thread上下文類加載器以及許多其他隱藏的問題。
幸運的是,有一種方法可以讓Java EE服務器通過Java EE 6 @Asynchronous
和這種聰明的設計模式來管理線程池。 可移植到任何Java EE 6認證的服務器。
在您的應用程序中創建此EJB。
package org.superbiz;
import javax.ejb.Asynchronous;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
@Stateless(name="Executor")
public class ExecutorBean implements Executor {
@Asynchronous
@Override
public void execute(Runnable command) {
command.run();
}
}
然后,您可以通過普通依賴注入(如果引用組件是Servlet,Listener,Filter,其他EJB,JSF Managed bean)在您的應用程序的其他位置引用此bean。
@EJB
private Executor executor;
然后像往常一樣使用Executor
。
如果組件不是另一個Java EE組件,則可以通過以下方式查找bean:
InitialContext initialContext = new InitialContext();
Executor executor = (Executor) initialContext.lookup("java:module/Executor");
嗯......大衛的解決方案對我不起作用,原因如下:
這是我做的:
我的安裝:
- JBOSS AS 7.1.1
- Java 1.6
- RHEL
- 使用Gradle和Arquillian運行示例:
@Stateless
public class ExecutorBean {
@Asynchronous
public void execute(Runnable command) {
command.run();
}
}
然后你的客戶端看起來像這樣:
@EJB ExecutorBean eb;
@Test
public void testExecutorBean() {
eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff());
assertFalse(!true);
}
但請注意:在我的standalone.xml中(或者一般來說我的JBOSS配置文件中有一個'線程池'部分。看看它(如果你碰巧使用JBOSSAS)並修改那里的值。找出來它是如何表現的。當我使用帶有arquillian測試的線程時,我得到的線程雖然我的保持時間非常高但已被殺死。我認為這與arquillian microdeploys有關。當arquillian完成所有未完成的線程被殺死時正在運行測試正在進行中......至少這是我認為我觀察到的。另一方面,所有完成的線程實際上表現得很好,他們完成了任務/操作。
希望這篇文章有幫助!
在EE7之前,您可能希望使用JSR 237中的WorkManager
http://docs.oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html
此規范目前已撤銷,仍有一些應用服務器實現它。 我在WebSphere 8.5中使用ibm實現 - IBM WorkManager 。 它是完全托管的資源,可在管理控制台中使用。 請注意,它與Oracle不兼容。
以下是IBM版本的示例:
@Resource(lookup = "wm/default")
WorkManager workManager;
public void process() {
try {
ArrayList<WorkItem> workItems = new ArrayList<WorkItem>();
for (int i = 0; i < 100; i++) {
// submit 100 jobs
workItems.add(workManager.startWork(new Work() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " Running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void release() {
System.out.println(Thread.currentThread().getName() + " Released");
}
}));
}
// wait for all jobs to be done.
workManager.join(workItems, WorkManager.JOIN_AND, 100000);
} catch (WorkException e) {
e.printStackTrace();
}
}
我也知道Commonj Workmanager 。
如果您使用的是JBoss,則可以使用org.jboss.seam.async.ThreadPoolDispatcher。
ThreadPoolDispatcher是完全托管的。
對於其他有用的托管類,請參閱包:org.jboss.seam.async。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.