Java thread Pool Detailed

Source: Internet
Author: User

Why do I need several parameters to construct a thread pool? What if you avoid an oom in the thread pool? Runnableand Callable What is the difference? These questions will be answered in this article, along with common scenarios and code snippets that use the thread pool.

Basic knowledge executors creating a thread pool

Creating a thread pool in Java is simple enough to invoke the Executors appropriate convenient method, for example Executors.newFixedThreadPool(int nThreads) , but convenience not only hides the complexity, but also buries the potential pitfalls (OOM, thread exhaustion).

ExecutorsTo create a thread pool convenient method list:

Method Name function
Newfixedthreadpool (int nthreads) Create a fixed-size thread pool
Newsinglethreadexecutor () Create a thread pool with only one threads
Newcachedthreadpool () Create a thread pool with an unlimited number of threads, and any submitted tasks will be executed immediately

There's nothing wrong with using these shortcuts for small programs, and for programs that need to run for a long time on the server, create a constructor that the thread pool should use directly ThreadPoolExecutor . Yes, Executors the thread pool created by the above method is ThreadPoolExecutor .

Threadpoolexecutor Construction Method

ExecutorsThe shortcut method for creating the thread pool in, in effect, is the constructor method that was called ThreadPoolExecutor (used by the timer task ScheduledThreadPoolExecutor ), and the constructor parameter list is as follows:

// Java线程池的完整构造函数public ThreadPoolExecutor(  int corePoolSize, // 线程池长期维持的线程数,即使线程处于Idle状态,也不会回收。  int maximumPoolSize, // 线程数的上限  long keepAliveTime, TimeUnit unit, // 超过corePoolSize的线程的idle时长,                                     // 超过这个时间,多余的线程会被回收。  BlockingQueue<Runnable> workQueue, // 任务的排队队列  ThreadFactory threadFactory, // 新线程的产生方式  RejectedExecutionHandler handler) // 拒绝策略

There are 7 parameters, very helpless, the construction of a thread pool does require so many parameters. Among these parameters, it is more likely to cause problems, corePoolSize maximumPoolSize workQueue as well handler :

    • corePoolSizeand maximumPoolSize improper setting can affect efficiency and even deplete threads;
    • workQueueImproper setting can lead to oom;
    • handlerImproper setting causes an exception to be thrown when the task is submitted.

The correct parameter setting is given below.

The working order of the thread pool

If fewer than corepoolsize threads is running, the Executor always prefers adding a new thread rather than queuing.
If corepoolsize or more threads is running, the Executor always prefers queuing a request rather than adding a new thread .
If a request cannot be queued, a new thread was created unless this would exceed maximumpoolsize, in which case, the task W Ill be rejected.

Corepoolsize, maximumpoolsize, task queue, deny policy

Runnable and callable

There are two types of tasks that can be submitted to the thread pool: Runnable and Callable , the difference is as follows:

    1. Method signatures are different, void Runnable.run()V Callable.call() throws Exception
    2. Whether a return value is allowed, Callable a return value is allowed
    3. Whether to allow exceptions to be thrown, and to Callable allow exceptions.

Callableis an interface added when JDK1.5, as a Runnable supplement that allows the return value to be allowed to throw an exception.

Three ways to submit tasks:
How to submit whether to care about returning results
Future<T> submit(Callable<T> task) Is
void execute(Runnable command) Whether
Future<?> submit(Runnable task) No, although it returns to the future, its get () method always returns null
How to use the thread pool correctly to avoid using unbounded queues

Do not use Executors.newXXXThreadPool() the shortcut method to create the thread pool, because this way will use the unbounded task queue, in order to avoid oom, we should use ThreadPoolExecutor the construction method to manually specify the maximum length of the queue:

ExecutorService executorService = new ThreadPoolExecutor(2, 2,                 0, TimeUnit.SECONDS,                 new ArrayBlockingQueue<>(512), // 使用有界队列,避免OOM                new ThreadPoolExecutor.DiscardPolicy());
Behavior when a task is explicitly rejected

When the task queue always fills up, what happens when submit() you submit a new task? RejectedExecutionHandlerinterface provides us with a control method, the interface is defined as follows:

public interface RejectedExecutionHandler {    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);}

The thread pool provides us with several common rejection strategies:

Deny Policy rejection Behavior
AbortPolicy Throw Rejectedexecutionexception
Discardpolicy Don't do anything, just ignore it.
Discardoldestpolicy Discard the oldest task in the execution queue and try to make a location for the currently committed task
Callerrunspolicy This task is performed directly by the person submitting the task

The default deny behavior of the thread pool is AbortPolicy to throw an RejectedExecutionHandler exception, which is a non-subject exception, and it is easy to forget the capture. If you do not care about the event that the task is rejected, you can set the Deny policy DiscardPolicy so that unnecessary tasks are silently ignored.

ExecutorService executorService = new ThreadPoolExecutor(2, 2,                 0, TimeUnit.SECONDS,                 new ArrayBlockingQueue<>(512),                 new ThreadPoolExecutor.DiscardPolicy());// 指定拒绝策略
Get processing results and exceptions

The processing results of the thread pool, as well as the exceptions in the processing process, are wrapped and Future Future.get() obtained when the method is called, and exceptions in the execution process are wrapped, and the ExecutionException submit() method itself does not pass the results and exceptions during task execution. The code that gets the execution result can be written like this:

ExecutorService executorService = Executors.newFixedThreadPool(4);Future<Object> future = executorService.submit(new Callable<Object>() {        @Override        public Object call() throws Exception {            throw new RuntimeException("exception in call~");// 该异常会在调用Future.get()时传递给调用者        }    });    try {  Object result = future.get();} catch (InterruptedException e) {  // interrupt} catch (ExecutionException e) {  // exception in Callable.call()  e.printStackTrace();}

The above code output looks like this:

Common scenarios for thread pools construct thread pools correctly
int poolSize = Runtime.getRuntime().availableProcessors() * 2;BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(512);RejectedExecutionHandler policy = new ThreadPoolExecutor.DiscardPolicy();executorService = new ThreadPoolExecutor(poolSize, poolSize,    0, TimeUnit.SECONDS,            queue,            policy);
Get a single result

submit()when a task is submitted to the thread pool, it returns one Future , and the calling V Future.get() method blocks the wait execution result, and the V get(long timeout, TimeUnit unit) method can specify the time-out to wait.

Get multiple results

If you submit multiple tasks to the thread pool to get the results of the execution of those tasks, you can call get in turn Future.get() . But for this scenario, we should use Executorcompletionservice, which take() always blocks the object that waits for a task to complete and then returns the task Future . CompletionServiceafter you submit a task in bulk, CompletionService.take() you can get the execution results of all tasks by calling the same number of times, whichever is the order of completion of the task:

void solve(Executor executor, Collection<Callable<Result>> solvers)   throws InterruptedException, ExecutionException {      CompletionService<Result> ecs = new ExecutorCompletionService<Result>(executor);// 构造器      for (Callable<Result> s : solvers)// 提交所有任务       ecs.submit(s);          int n = solvers.size();   for (int i = 0; i < n; ++i) {// 获取每一个完成的任务       Result r = ecs.take().get();       if (r != null)           use(r);   }}
Time-out for a single task

V Future.get(long timeout, TimeUnit unit)Method can specify the time-out to wait, and the timeout is not completed TimeoutException .

Time-outs for multiple tasks

Wait for multiple tasks to complete and set the maximum wait time, which can be done by Countdownlatch:

public void testLatch(ExecutorService executorService, List<Runnable> tasks)     throws InterruptedException{          CountDownLatch latch = new CountDownLatch(tasks.size());      for(Runnable r : tasks){          executorService.submit(new Runnable() {              @Override              public void run() {                  try{                      r.run();                  }finally {                      latch.countDown();// countDown                  }              }          });      }      latch.await(10, TimeUnit.SECONDS); // 指定超时时间  }
Thread pool and decoration company

To run a decoration company to do a metaphor. The company waits for the customer to submit the decoration request in the Office place, the company has the fixed quantity official work to maintain the operation; When high season business is more, the new customer request will be scheduled, for example, after the Tanjo tells the user one months to start the renovation; Acquaintance introduction, etc.) hire some temporary workers (note that the hiring of temporary workers after the schedule is full); If temporary workers are too busy, the company will decide not to accept new customers and direct rejection.

Thread pool is the "decoration Company" in the program, do all kinds of dirty live dirty. The above procedure corresponds to the thread pool:

// Java线程池的完整构造函数public ThreadPoolExecutor(  int corePoolSize, // 正式工数量  int maximumPoolSize, // 工人数量上限,包括正式工和临时工  long keepAliveTime, TimeUnit unit, // 临时工游手好闲的最长时间,超过这个时间将被解雇  BlockingQueue<Runnable> workQueue, // 排期队列  ThreadFactory threadFactory, // 招人渠道  RejectedExecutionHandler handler) // 拒单方式
Summarize

ExecutorsProvides us with a convenient way to construct the thread pool, for server programs we should eliminate the use of these convenient methods, but directly use the thread pool ThreadPoolExecutor construction method, to avoid the possibility of an unbounded queue of oom and the number of threads caused by improper number of thread exhaustion, and so on. ExecutorCompletionServiceprovides an effective way to wait for the end of all tasks, and if you want to set the waiting time-out, you can do so by CountDownLatch completing.

Reference

Threadpoolexecutor API Doc

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.