如何正确使用Java Executor? [英] How to properly use Java Executor?

查看:46
本文介绍了如何正确使用Java Executor?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在多线程应用程序中使用过Java Executor,但是我似乎无法弄清楚何时最好使用以下每种方式:

I've used Java Executors in my multi-threading apps, but I can't seem to figure out when is the best to use each of the following ways:

1.

ExecutorService executor=Executors.newFixedThreadPool(50);
executor.execute(new A_Runner(... some parameter ...));
executor.shutdown();
while (!executor.isTerminated()) { Thread.sleep(100); }

2.

int Page_Count=200;
ExecutorService executor=Executors.newFixedThreadPool(50);
doneSignal=new CountDownLatch(Page_Count);
for (int i=0;i<Page_Count;i++) executor.execute(new A_Runner(doneSignal, ... some parameter ...));
doneSignal.await();
executor.shutdown();
while (!executor.isTerminated()) { Thread.sleep(100); }

3.

int Executor_Count=30;
ThreadPoolExecutor executor=new ThreadPoolExecutor(Executor_Count,Executor_Count*2,1,TimeUnit.SECONDS,new LinkedBlockingQueue());
List<Future<String>> futures=new ArrayList<>(3330);

for (int i=0;i<50;i++) futures.add(executor.submit(new A_Runner(... some parameter ...));
executor.shutdown();
while (!executor.isTerminated()) { executor.awaitTermination(1,TimeUnit.SECONDS); }
for (Future<String> future : futures)
{
    String f=future.get();
    // ...
}

具体来说,在[2]中,如果我跳过doneSignal,那会像[1]一样,那么doneSignal的用途是什么?

Specifically, in [2] what if I skip the doneSignal, then it'll be like [1], so what's the use for the doneSignal?

另外,在[3]中,如果我添加了doneSignal,该怎么办?还是有可能?

Also, in [3], what if I add a doneSignal? Or is it possible?

我想知道的是:这些方法是可以互换的,还是在某些情况下我应该使用上面的特定类型?

What I'd like to know is : are these approaches interchangeable, or is there a certain situation that I'm supposed to use a specific type above?

推荐答案

  1. ExecutorService

ExecutorService executor=Executors.newFixedThreadPool(50);

简单易用.它隐藏了ThreadPoolExecutor的低级详细信息.

It is simple and easy to use. It hides low level details of ThreadPoolExecutor.

Callable/Runnable个任务的数量很少并且无限制队列中的任务堆积不会增加内存时,请选择此选项.降低系统性能.如果您有CPU/Memory约束,请将ThreadPoolExecutor与容量约束& RejectedExecutionHandler处理拒绝任务.

Prefer this one when number of Callable/Runnable tasks are small in number and piling of tasks in unbounded queue does not increase memory & degrade the performance of the system. If you have CPU/Memory constraints, use ThreadPoolExecutor with capacity constraints & RejectedExecutionHandler to handle rejection of tasks.

CountDownLatch

您已经用给定的计数初始化了CountDownLatch.通过调用countDown()方法,此计数减少.我假设您稍后在Runnable任务中调用递减.等待该计数达到零的线程可以调用await()方法之一.调用await()会阻塞线程,直到计数达到零为止. 该类使Java线程可以等待其他线程集完成其任务.

You have initialized CountDownLatch with a given count. This count is decremented by calls to the countDown() method. I am assuming that you are calling decrement in your Runnable task later. Threads waiting for this count to reach zero can call one of the await() methods. Calling await() blocks the thread until the count reaches zero. This class enables a java thread to wait until other set of threads completes their tasks.

用例:

  1. 实现最大并行度:有时我们想同时启动多个线程以实现最大并行度

  1. Achieving Maximum Parallelism: Sometimes we want to start a number of threads at the same time to achieve maximum parallelism

等待N个线程在开始执行之前完成

Wait N threads to completes before start execution

死锁检测.

看看这个 Lokesh Gupta的文章以获取更多详细信息.

Have a look at this article by Lokesh Gupta for more details.

  • ThreadPoolExecutor :它提供了更多控制来微调各种线程池参数.如果您的应用程序受到活动的Runnable/Callable任务数量的限制,则应通过设置最大容量来使用有界队列.一旦队列达到最大容量,就可以定义RejectionHandler. Java提供了四种RejectedExecutionHandler 政策 a>.

  • ThreadPoolExecutor : It provides more control to finetune various thread pool parameters. If your application is constrained by number of active Runnable/Callable tasks, you should use bounded queue by setting the max capacity. Once the queue reaches maximum capacity, you can define RejectionHandler. Java provides four types of RejectedExecutionHandler policies.

    1. 在默认的ThreadPoolExecutor.AbortPolicy中,处理程序在拒绝时会抛出运行时RejectedExecutionException.

    1. In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.

    ThreadPoolExecutor.CallerRunsPolicy中,调用执行自己的线程运行任务.这提供了一种简单的反馈控制机制,可以降低新任务的提交速度.

    In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.

    ThreadPoolExecutor.DiscardPolicy中,简单地删除了无法执行的任务.

    In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.

    ThreadPoolExecutor.DiscardOldestPolicy中,如果未关闭执行程序,则将丢弃工作队列开头的任务,然后重试执行(该操作可能再次失败,导致重复执行此操作.)

    In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)

    如果要模拟CountDownLatch行为,则可以使用invokeAll()方法.

    If you want to simulate CountDownLatch behaviour, you can use invokeAll() method.

  • 您未引用的另一种机制是 ForkJoinPool已在Java 7中添加到Java.ForkJoinPool与 Java ExecutorService,但有一个区别. ForkJoinPool使其成功 任务很容易将其工作分解为较小的任务,然后 也提交给ForkJoinPool.当空闲的工作线程从繁忙的工作线程队列中窃取任务时,ForkJoinPool中发生任务窃取.

    The ForkJoinPool was added to Java in Java 7. The ForkJoinPool is similar to the Java ExecutorService but with one difference. The ForkJoinPool makes it easy for tasks to split their work up into smaller tasks which are then submitted to the ForkJoinPool too. Task stealing happens in ForkJoinPool when free worker threads steal tasks from busy worker thread queue.

    Java 8在 ExecutorService 创建工作窃取池.您不必创建RecursiveTaskRecursiveAction,但仍可以使用ForkJoinPool.

    Java 8 has introduced one more API in ExecutorService to create work stealing pool. You don't have to create RecursiveTask and RecursiveAction but still can use ForkJoinPool.

      public static ExecutorService newWorkStealingPool()
    

    使用所有可用处理器作为目标并行度级别来创建窃取线程的池.

    Creates a work-stealing thread pool using all available processors as its target parallelism level.

    默认情况下,它将使用CPU内核数作为参数.

    By default, it will take number of CPU cores as parameter.

    所有这四种机制都是相互补充的.根据要控制的粒度级别,您必须选择正确的粒度.

    All these four mechanism are complimentary to each other. Depending on level of granularity you want to control, you have to chose right ones.

    这篇关于如何正确使用Java Executor?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆