Jboss Java EE container and an ExecutorService

后端 未结 5 1750
滥情空心
滥情空心 2020-11-29 01:53

I have a standalone java app which used the ExecutorService to process a number of jobs in parallel

 ExecutorService es = Executors.newFixedThreadPool(10);
<         


        
相关标签:
5条回答
  • 2020-11-29 02:23

    Obligatory warning: Creating your own threads in a Java EE app server (even Tomcat) is discouraged as it can be a huge performance issue and in most cases will prevent container functionality, such as JNDI, from working. The new threads won't know which application they belong to, the Thread context classloader will not be set and many other hidden issues.

    Fortunately there is a way to get the Java EE server to manage the thread pool via the Java EE 6 @Asynchronous and this clever design pattern. Portable to any Java EE 6 certified server.

    Create this EJB in your application.

    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();
        }
    }
    

    Then you can refer to this bean elsewhere in your application via plain dependency injection (if the referring component is a Servlet, Listener, Filter, other EJB, JSF Managed bean).

    @EJB
    private Executor executor;
    

    Then use the Executor as normal.

    If the component is not another Java EE component, you can lookup the bean via:

    InitialContext initialContext = new InitialContext();
    Executor executor = (Executor) initialContext.lookup("java:module/Executor");
    
    0 讨论(0)
  • 2020-11-29 02:27

    Well... David's solution did not work for me for the following reasons:

    1. Compiler was bitching around that java.util.concurrent is not allowed... which kinda makes sense in JBOSS scope.
    2. Also: public STATIC class...? Read this up: Why are you not able to declare a class as static in Java?

    Here's what I did:
    My installation:
    - JBOSS AS 7.1.1
    - Java 1.6
    - RHEL
    - Running the example with Gradle and Arquillian:

    @Stateless
    public class ExecutorBean {
        @Asynchronous
        public void execute(Runnable command) {
            command.run();    
        }
    }
    

    Then your client looks like this:

    @EJB ExecutorBean eb;
    @Test
    public void testExecutorBean() {
        eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff());
        assertFalse(!true);
    }
    

    Beware, though: In my standalone.xml (or generally speaking my config file for JBOSS I have a section 'thread-pools'. Have a look at it (if you happen to use JBOSSAS) and tinker with the values there. Find out how it behaves. When I use threads with arquillian tests I get threads that are killed though my keepalive-time is very high. I think this has to do with how arquillian microdeploys. When arquillian finishes all non-finished threads are killed which were running whilst the tests are being run... at least that is what I think I observe. On the other hand all finished threads actually behaved well in that sense that they completed their tasks/operations.

    Hope this post helps!

    0 讨论(0)
  • 2020-11-29 02:28

    The correct way to do this in your EJB is to use the ManagedExecutorService, which is part of the Concurrency Utils API (Java EE7). You shouldn't be using any ExecutorService that is part of the java.util.concurrent in your enterprise code.

    By using the ManagedExecutorService your new thread will be created and managed by the container.

    The following example is taken from my site here.

    To create a new thread using a ManagedExecutorService, first create a task object that implements Callable. Within the call() method we will define the work that we want carried out in a separate thread.

    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();
        }
    }
    

    Then we need to invoke the task by passing it though to the submit() method of the ManagedExecutorService.

    @Stateless
    public class ReportBean {
    
        @Resource
        private ManagedExecutorService executorService;
    
        public void runReports() {
            ReportTask reportTask = new ReportTask();
            Future<Report> future = executorService.submit(reportTask);
        }
    }
    
    0 讨论(0)
  • 2020-11-29 02:42

    Prior to EE7, you might want to use WorkManager from JSR 237

    http://docs.oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html

    This spec is currently withdrawn, still some app servers implement it. I use ibm implementation in WebSphere 8.5 - IBM WorkManager. It is fully managed resource, available in administration console. Please note that it is not interface-compatible with Oracle.

    Here is an example for IBM version:

    @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();
        }
    }
    

    Also I am aware of Commonj Workmanager.

    0 讨论(0)
  • 2020-11-29 02:47

    If you are using JBoss, you can use org.jboss.seam.async.ThreadPoolDispatcher.

    ThreadPoolDispatcher is completely managed.

    For others useful managed classes, see the package: org.jboss.seam.async.

    0 讨论(0)
提交回复
热议问题