简体   繁体   English

我应该在后端(在 Java 中)使用 WorkManager 进行多线程处理吗?

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

I work on the backend of a java web application.我在 Java Web 应用程序的后端工作。 I added some multithreading to speed up a big data retrieval, and I used a few ExecutorServices I created in the process.我添加了一些多线程来加速大数据检索,并使用了我在此过程中创建的一些 ExecutorServices。 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.但是,我读到在 Web 应用程序中以这种方式创建线程可能不是一个好主意,而 'com.ibm.websphere.asynchbeans.WorkManager' 可能是一个选项。 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'.根据文档,工作管理器是“为使用异步 bean 的 Java Platform, Enterprise Edition (Java EE) 应用程序创建的线程池”。 I, as a very front end ignorant back end guy, don't even entirely know what a bean is.我,作为一个对前端非常无知的后端家伙,甚至不完全知道 bean 是什么。 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.看起来工作经理并不是我想要的,但如果手动创建 ExecutorService 实际上是个坏主意,我不确定最好的方法是什么。

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.由于以下原因,在 web 应用程序的后端创建您自己的线程是一个坏主意:Application Server 容器为您管理线程。 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.理论上最好的方法是在你的 App Server 中注册一些线程池,并使用 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.因此,在这种情况下ExecutorService是最好的方法,因为它提供了非常好的 API 来管理您的线程。 Just make sure that as your application shuts down you shutdown your ExecutorService so no orphan threads are left behind.只需确保在您的应用程序关闭时关闭您的ExecutorService这样就不会留下孤立线程。 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.只需谨慎使用它们,并注意在完成或应用程序关闭时关闭ExecutorService BTW there is a similar issue with ThreadLocal variables.顺便说一句, ThreadLocal变量也有类似的问题。 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.完成后,您绝对必须在其中调用 metod remove() ,否则即使您的应用程序关闭,它们也会保留在内存中,并且只有应用程序服务器重新启动才会清除它们。 This is a dangerous memory leak.这是一个危险的内存泄漏。

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:只是为了扩展 Michael Gantman 的回答,这是一个很好的解释,允许容器管理线程池的 JavaEE 方法非常容易实际实现:

@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. @Aysnchronous负责处理这里的魔法,向容器指定应该异步调用这个函数,并且容器有责任弄清楚这意味着什么。 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 .查看这些以获取更多阅读: javax.ejb.AsynchronousAsynchronous 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:由于我知道您使用的是 IBM 产品,因此在 JBoss 中,您的异步作为子系统配置的一部分通过指定<async thread-pool-name="poolName"/> ( https://docs .jboss.org/author/display/WFLY8/EE+Subsystem+Configuration ) 其中poolName应该引用一个池,例如:

<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:但是,如果您尝试提交一些任务到ExecutorService可以由容器管理,则有更好的方法:

@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;在那之前,我最初使用@Asynchronous线程池作为执行器在这里发布了一些内容,但这是不必要的,因为容器应该已经为您准备好了; 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 .同样,这可能有点特定于 JBoss,但在 JBoss 中,它被配置为一个子系统managed-scheduled-executor-servicesmanaged-executor-services These two subsystems have their own distinct thread pools that they utilize.这两个子系统有自己独特的线程池供它们使用。

EDIT April, 2020编辑 2020 年 4 月

So I somehow found this answer again, and reread and am very confused at myself for not calling out the EJB specification explicitly.所以我以某种方式再次找到了这个答案,并重新阅读并且对自己没有明确调用 EJB 规范感到非常困惑。 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.这样做不仅是个坏主意,而且如果您创建自己的线程,将直接违反 EJB 规范。

JSR 345: Enterprise JavaBeans, Version 3.2 EJB Core Contracts and Requirements JSR 345:企业 JavaBeans,3.2 版 EJB 核心契约和要求

Section 16.2.2 Bean Provider's Responsibilities, Programming Restrictions:第 16.2.2 节 Bean Provider 的职责,编程限制:

  • The enterprise bean must not attempt to manage threads.企业 bean 不得尝试管理线程。 The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread's priority or name.企业 bean 不得尝试启动、停止、挂起或恢复线程,或者更改线程的优先级或名称。 The enterprise bean must not attempt to manage thread groups.企业 bean 不得尝试管理线程组。

These functions are reserved for the EJB container.这些函数是为 EJB 容器保留的。 Allowing the enterprise bean to manage threads would decrease the container's ability to properly manage the runtime environment.允许企业 bean 管理线程会降低容器正确管理运行时环境的能力。

In other words, NEVER attempt to manage your own threads in a web application.换句话说,永远不要尝试在 Web 应用程序中管理您自己的线程。 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() ).此引用适用于 EJB 规范,但即使在 ResourceAdapter 中,例如,容器也通过BootstrapContext提供WorkManager (请参阅ResourceAdapter#start(BootstrapContext)BootstrapContext#getWorkManager() )。 There's never a reason to attempt to create/manage your own thread in a web application;永远没有理由尝试在 Web 应用程序中创建/管理您自己的线程; never do it for any reason.永远不要以任何理由这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM