Technology and optimization of thread pooling in Java

Source: Internet
Author: User
Tags cpu usage

The reason for writing this article is because there is a project in the team that uses the technology and has a performance problem. I personally have a lot of interest in this issue.

private static Threadfactory threadfactory = new Threadfactorybuilder (). Setnameformat ("Threadpoolname"). Build ();
 private static Threadpoolexecutor Executorservice = new Threadpoolexecutor (0, Timeunit.milliseconds, new SYNCHR Onousqueue<> (), Threadfactory, New Threadpoolexecutor.callerrunspolicy ());

Create a demo of the thread pool

Parameter initialization private static final int cpu_count = Runtime.getruntime (). Availableprocessors ();
Core thread number size private static final int corepoolsize = Math.max (2, Math.min (Cpu_count-1, 4));
thread pool maximum hold thread number private static final int maximumpoolsize = Cpu_count * 2 + 1;

When the thread is idle, the long private static final int keepalivetime = 30;

After too many tasks, a blocking queue for the storage task blockingqueue<runnable> Workqueue = new synchronousqueue<> (); Thread Creation Factory Threadfactory threadfactory = new Threadfactory () {private final Atomicinteger Mcount = new Atomicinteger (1

    );
    Public thread Newthread (Runnable r) {return new Thread (R, "Advacnedasynctask #" + mcount.getandincrement ());

}
};

Task rejection policy Rejectedexecutionhandler Rejecthandler = new Threadpoolexecutor.discardoldestpolicy () when the thread pool task is loaded
        Thread pool objects, creating threads threadpoolexecutor Mexecute = new Threadpoolexecutor (corepoolsize, Maximumpoolsize, KeepAliveTime, Timeunit.seconds, Workqueue, Threadfactory, RejecthaNdler); 



I studied the online articles for reference as follows:

Thread Pool Introduction: http://www.jianshu.com/p/87bff5cc8d8c

Principle and suggestion of thread pool: http://www.infoq.com/cn/articles/java-threadPool#anch151278

Reject Policy: http://wangkuiwu.github.io/2012/08/15/juc-executor05/

In the above data mentioned Newscheduledthreadpool this thread pool application scenario.

This thread pool can be used periodically to synchronize data in a real business scenario.

The most interesting of these is the Execute method:

The specific implementation process is as follows:
1. The Workercountof method obtains the current number of threads in the thread pool according to the low 29 bits of the CTL, and executes the Addworker method to create a new thread execution task if the number of threads is less than corepoolsize; otherwise execute steps (2);
2. If the thread pool is in a running state and the submitted task is successfully placed in the blocking queue, then the step (3) is performed, otherwise the steps (4) are performed;
3, again check the state of the thread pool, if the thread pool is not running, and successfully remove the task from the blocking queue, then execute the Reject method processing task;
4, execute the Addworker method to create a new thread to perform the task, if Addwoker execution fails, execute the Reject method to process the task;

* * Proceed in 3 steps: * * 1.
         If fewer than corepoolsize threads are running, try to * start a new thread with the given command as its  * Task.
         The call to Addworker atomically checks runstate and * workercount, and I prevents false alarms that would add
         * Threads when it shouldn ' t, by returning false. * * 2.
         If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry to this me Thod. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if th
         ere are none. * * 3.  If We cannot queue task, then we try to add a new * thread.
         If it fails, we know we are shut down or saturated * and so reject the task. */


The thread pool usage process:

If the number of worker threads in the current pool is less than corepoolsize, a new worker thread is created to perform this task, regardless of whether the thread is idle in the worker-thread collection. If there are more work threads than corepoolsize in the pool but smaller than maximumpoolsize, the task is first tried to put in the queue, and there are two situations that need to be said individually: A, if the task is successfully put into the queue, see if you need to open a new thread to perform the task. A new thread is created only if the current number of worker threads is 0, because the previous thread might have been removed because it was idle or because the work ended.

b, if the queue fails, the new worker thread is created. If the corepoolsize and Maximumpoolsize are the same, the thread pool size is fixed. By setting the maximumpoolsize to infinity, we can get a thread pool with no caps. In addition to setting these thread pool parameters by constructing parameters, we can set them at run time.

core Thread Warmup optimization

By default, core worker thread values are created at the initial time, and are started when new tasks come in, but we can change this behavior by rewriting the Prestartcorethread or Prestartcorethreads methods. Usually we can warmup the core thread when the application is started, so that the result of the task can be executed immediately, and the time of the initial task processing will be optimized.

customizing worker thread creation Optimization

New threads are created by threadfactory, and if not specified, the default executors#defaultthreadfactory will be used, and the threads created at this time will all belong to the same thread group, with the same priority and daemon status. Extended configuration Threadfactory, we can configure the thread's name, thread combination daemon state. If the call to Threadfactory#createthread fails, returning Null,executor will not perform any tasks.

Core Thread Recycling

If the number of worker threads in the current pool is greater than corepoolsize, if the thread exceeding this number is idle for more than KeepAliveTime, the threads will be terminated, which is a strategy to reduce unnecessary resource consumption. This parameter can be changed at runtime and we can also apply this strategy to the core thread, which we can implement by invoking Allowcorethreadtimeout.


correct selection of queues

The following are mainly the performance of different queue strategies:

Direct submission: A better default option is to use Synchronousqueue, which sends the submitted task directly to the worker thread without holding it. If there are currently no worker threads to process, that is, the task is queued for failure, a new worker thread creation is raised based on the thread pool implementation, so the newly submitted task is processed. This strategy avoids the lock contention consumption when there is a dependency between the submitted batch of tasks. It is worth mentioning that this strategy is best used in conjunction with the number of unbounded threads to prevent the task from being rejected. At the same time, we have to take into account a scenario where the speed at which a task arrives is greater than the speed at which the task is processed, resulting in an unlimited number of threads increasing.

Unbounded queues: Using unbounded queues such as linkedblockingqueue without specifying the maximum capacity will cause a new task to be placed on the queue when the core threads are busy, so there will never be any threads greater than corepoolsize created, Therefore, the Maximumpoolsize parameter will fail. This strategy is more suitable for all tasks are not interdependent, independent implementation. For example, in a Web server, each thread handles the request independently. But when the task processing speed is smaller than the task to enter the speed of the queue will cause infinite expansion.

Bounded queues: Bounded queues such as Arrayblockingqueue help limit resource consumption, but are not easily controlled. The two values of queue length and maximumpoolsize affect each other, and using large queues and small maximumpoolsize reduces CPU usage, operating system resources, and context switch consumption, but reduces throughput if tasks are frequently blocked such as IO threads, The system can actually schedule more threads. Using small queues usually requires large maximumpoolsize, which makes the CPU busier, but increases the consumption of thread scheduling that reduces throughput. To summarize is IO-intensive can consider more threads to balance CPU usage, CPU-intensive can consider less thread to reduce the consumption of thread scheduling.
a reasonable configuration thread pool

To properly configure the thread pool, you must first analyze the task attributes, and you can analyze them from the following perspectives: The Nature of the task: CPU-intensive, IO-intensive, and hybrid tasks. Priority of tasks: high, Medium, and low. Task execution time: Long, medium, and short. task dependencies: Whether to rely on other system resources, such as database connections.

Tasks of a different nature can be handled separately with different sizes of thread pools. CPU-intensive tasks are configured with as small a thread as possible, such as a thread pool that configures ncpu+1 threads. IO-intensive tasks Configure as many threads as possible, such as 2*NCPU, because the threads are not always performing tasks. A mixed type of task, if it can be split, split it into a CPU-intensive task and an IO-intensive task, so long as the two tasks do not perform as much time as they do, the throughput performed after the decomposition is higher than the serial execution throughput, and if the two task execution times vary significantly, there is no need to decompose. We can get the number of CPUs for the current device through the Runtime.getruntime (). Availableprocessors () method.

Tasks with different priorities can be handled using the priority queue Priorityblockingqueue. It allows high-priority tasks to be executed first, and it should be noted that if a high-priority task is committed to the queue, the lower-priority task may never be executed.

Tasks with different execution times can be assigned to different sizes of thread pools, or priority queues can be used to allow tasks with short execution time to be executed first.

Rely on the database connection pool task because the thread submits SQL and waits for the database to return results, and if the longer the CPU is idle, the larger the number of threads should be set, so that the CPU can be better utilized.

The proposed use of bounded queues, bounded queues can increase the stability of the system and early warning capabilities, can be set to a larger point, such as thousands of. Once the queue and thread pool of the background task thread pool used by our group was full, constantly throw out the exception of the task, by troubleshooting found that there is a database problem, resulting in the execution of SQL is very slow, because the background task line Cheng Chili task is to query and insert data to the database, Therefore lead to line Cheng Chili work thread all block live, task backlog online Cheng Chili. If we were to set up a unbounded queue, the queue of thread pool would be more and more, it might be full of memory, cause the whole system is not available, not only the background task problems. Of course all of our systems are deployed with separate servers, and we use different sizes of thread pools to run different types of tasks, but this problem can also affect other tasks. monitoring of thread pools

Monitored by the parameters provided by the thread pool. Line Cheng Chili There are some properties that you can use when monitoring the thread pool Taskcount: The number of tasks that the thread pool needs to perform. Completedtaskcount: The number of tasks that the thread pool has completed during the run. Less than or equal to Taskcount. Largestpoolsize: The maximum number of threads that the thread pool has ever created. This data lets you know if the thread pool is full. If the maximum size of the thread pool is equal, the thread pool is once full. Getpoolsize: The number of threads in the thread pool. If the thread pool is not destroyed, the threads in the pool are not automatically destroyed, so this size is only increased by No + Getactivecount: Gets the number of active threads.

Monitor by extending the thread pool. By inheriting the thread pool and overriding the Beforeexecute,afterexecute and terminated methods of the thread pool, we can do something before the task executes and before the thread pool closes. such as monitoring the average execution time of tasks, maximum execution time and minimum execution time, etc. These methods of online Cheng Chili are empty methods. Such as:

protected void BeforeExecute (Thread T, Runnable r) {}

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.