Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use a WorkManager for multithreading in the backend (in java)?

I work on the backend of a java web application. I added some multithreading to speed up a big data retrieval, and I used a few ExecutorServices I created in the process. However, I've read that it might not be a good idea to be creating threads this way in a web app, and that the 'com.ibm.websphere.asynchbeans.WorkManager' is maybe an option instead. It seems not very friendly to use in the backend though. According to the documentation, the work manager is a 'thread pool created for Java Platform, Enterprise Edition (Java EE) applications that use asynchronous beans'. I, as a very front end ignorant back end guy, don't even entirely know what a bean is. It doesn't really seem like the work manager is what I want, but if it's actually a bad idea to manually create an ExecutorService, I'm not sure what the best approach is.

like image 981
BradMicholson Avatar asked Nov 21 '25 08:11

BradMicholson


2 Answers

Creating your own threads in the back end of a webapp is a bad idea for the following reason: Application Server container manages threads for you. So if you create your own threads in your app the container won't know about them and won't be able to manage them. Thus if you mismanage threads your app can cause memory leaks and other thread related problems. In theory the best way is to register some thread pool in your App Server and requests threads from the container using JNDI. But it might be an overkill. So sometimes, you may want to manage your own threads. So, in this case ExecutorService is the best way to go as it provides very nice API to manage your threads. Just make sure that as your application shuts down you shutdown your ExecutorService so no orphan threads are left behind. If you are careful about it then you can create your own threads. Just use them sparingly and be careful that you you shut down your ExecutorService when done or when Application shuts down. BTW there is a similar issue with ThreadLocal variables. You absolutely MUST invoke metod remove() in them when done, otherwise they will remain in the memory even if your app is shutdown, and only Application Server restart will clear them. This is a dangerous memory leak.

like image 146
Michael Gantman Avatar answered Nov 22 '25 22:11

Michael Gantman


Just to expand on Michael Gantman's answer, which is a pretty good explanation, the JavaEE approach to allowing the container manage your threadpool is super easy to actually implement:

@Stateless
public class Foo {

    @Asynchronous
    @Override
    public void doSomething() {
        //all calls to this function are asynchronous
    }
}

The @Aysnchronous takes care of the magic here, specifying to the container that this function should be called asynchronously and it's the container's responsibility to figure out what that means. Then calling out to your container managed threadpool to execute your function is as simple as:

@Stateless
public class Bar {
    @EJB
    Foo myFooEJB;

    public void businessMethod() {
        myFooEJB.doSomething();
    }
}

Checkout these for more reading: javax.ejb.Asynchronous, Asynchronous method invocation. Getting maybe a little too into specifics because I know you're using IBM products, in JBoss, your Asynchronous comes as part of a subsystem configuration by specifying <async thread-pool-name="poolName"/> (https://docs.jboss.org/author/display/WFLY8/EE+Subsystem+Configuration) where poolName should reference a pool such as:

<thread-pools>
    <thread-pool name="poolName">
        <max-threads count="10"/>
        <keepalive-time time="100" unit="milliseconds"/>
    </thread-pool>
</thread-pools>

But there is a better way if you're trying to submit, just some task to an ExecutorService which can be managed by the container:

@Resource
ManagedExecutorService executorService;

@Resource
ManagedScheduledExecutorService scheduledExecutorService;

java.io.PrintWriter out = ...;

void scheduleSomeStuff(){
    scheduledExecutorService.schedule(new Runnable() {
        @Override
        public void run() {
            out.println("Print out after roughly 15 seconds.")
        }
    }, 15, TimeUnit.SECONDS);

    executorService.submit(new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            out.println("Print only once, when the task is run by the executor service's discretion.");
        }
    };
}

These two resources, specifically that I've reference here, run on different thread pools. At that, I originally posted something here using the @Asynchronous thread pool as an executor, but it's unnecessary since the container should already have one for you; hence the updated answer you see here now.

This, again, might be a little specific to JBoss, but in JBoss this is configured as a subsystem managed-scheduled-executor-services and managed-executor-services. These two subsystems have their own distinct thread pools that they utilize.

EDIT April, 2020

So I somehow found this answer again, and reread and am very confused at myself for not calling out the EJB specification explicitly. Not only is it a bad idea to do, you would be in direct violation of the EJB spec if you created your own threads.

JSR 345: Enterprise JavaBeans, Version 3.2 EJB Core Contracts and Requirements

Section 16.2.2 Bean Provider’s Responsibilities, Programming Restrictions:

  • The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups.

These functions are reserved for the EJB container. Allowing the enterprise bean to manage threads would decrease the container’s ability to properly manage the runtime environment.

In other words, NEVER attempt to manage your own threads in a web application. This quote is for the EJB spec but even within a ResourceAdapter, for example, the container provides a WorkManager via the BootstrapContext (see ResourceAdapter#start(BootstrapContext), BootstrapContext#getWorkManager()). There's never a reason to attempt to create/manage your own thread in a web application; never do it for any reason.

like image 26
searchengine27 Avatar answered Nov 22 '25 20:11

searchengine27