簡體   English   中英

Jboss Java EE容器和ExecutorService

[英]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");

嗯......大衛的解決方案對我不起作用,原因如下:

  1. 編譯器喋喋不休地說java.util.concurrent是不允許的......在JBOSS范圍內哪種方式有意義。
  2. 另外:公共STATIC課......? 閱讀本文: 為什么你不能在Java中將類聲明為靜態?

這是我做的:
我的安裝:
- JBOSS AS 7.1.1
- Java 1.6
- RHEL
- 使用GradleArquillian運行示例:

@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM