Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze and use Java thread pool

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

How to analyze and use Java thread pool? in view of this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

1. Introduction

Rational use of thread pools can bring three benefits.

First: reduce resource consumption. Reduce the consumption caused by thread creation and destruction by reusing created threads.

Second: improve the response speed. When a task arrives, it can be executed immediately without waiting for the thread to be created.

Third: improve the manageability of threads. Thread is a scarce resource, if it is created without restriction, it will not only consume system resources, but also reduce the stability of the system. Thread pool can be used for unified allocation, tuning and monitoring. However, in order to make rational use of thread pool, we must know its principle like the back of our hand.

two。 Usage of thread pool creation of thread pool

We can create a thread pool through ThreadPoolExecutor.

New ThreadPoolExecutor (corePoolSize, maximumPoolSize,keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler)

You need to enter several parameters to create a thread pool:

CorePoolSize (basic size of the thread pool): when a task is submitted to the thread pool, the thread pool creates a thread to execute the task, even if other idle basic threads are able to execute the new task, until the number of tasks that need to be executed is greater than the basic size of the thread pool. If the prestartAllCoreThreads method of the thread pool is called, the thread pool creates and starts all basic threads in advance.

RunnableTaskQueue (task queue): a blocking queue used to hold tasks waiting to be executed. You can select the following blocking queues.

1.ArrayBlockingQueue: a bounded blocking queue based on an array structure that sorts elements according to FIFO (first-in, first-out) principles.

2.LinkedBlockingQueue: a blocking queue based on a linked list structure that sorts elements by FIFO (first-in, first-out) and usually has higher throughput than ArrayBlockingQueue. The static factory method Executors.newFixedThreadPool () uses this queue.

3.SynchronousQueue: a blocking queue that does not store elements. Each insert operation must wait until another thread invokes the remove operation, otherwise the insert operation remains blocked and the throughput is usually higher than LinkedBlockingQueue, which is used by the static factory method Executors.newCachedThreadPool.

4.PriorityBlockingQueue: an infinite blocking queue with priority.

MaximumPoolSize (maximum thread pool size): the maximum number of threads allowed to be created by the thread pool. If the queue is full and the number of threads created is less than the maximum number of threads, the thread pool creates new threads to execute the task. It is worth noting that this parameter has no effect if you use an unbounded task queue.

ThreadFactory: used to set up the factory to create threads, you can use the thread factory to set a more meaningful name for each created thread, Debug and locate problems are very helpful.

RejectedExecutionHandler (saturation policy): when the queue and thread pool are full, indicating that the thread pool is saturated, a strategy must be adopted to deal with new tasks submitted. This policy defaults to AbortPolicy, which means that an exception is thrown when a new task cannot be processed. Here are four strategies provided by JDK1.5. N AbortPolicy: throw an exception directly.

1..CallerRunsPolicy: only use the caller's thread to run the task.

2.DiscardOldestPolicy: discard the most recent task in the queue and execute the current task.

3.DiscardPolicy: don't deal with it, discard it.

4. Of course, you can also implement the custom policy of RejectedExecutionHandler interface according to the needs of the application scenario. Such as logging or persisting tasks that cannot be handled.

KeepAliveTime (thread activity hold time): the amount of time that the worker thread of the thread pool remains alive after it is idle. So if there are many tasks, and the execution time of each task is relatively short, you can increase this time to improve thread utilization.

TimeUnit (unit of thread activity hold time): optional units are day (DAYS), hour (HOURS), minute (MINUTES), millisecond (MILLISECONDS), microsecond (MICROSECONDS, 1/1000 millisecond) and nanosecond (NANOSECONDS, 1/1000 picosecond).

Submit tasks to the thread pool

We can use the task submitted by execute, but the execute method does not return a value, so it is impossible to determine whether the task was successfully executed by the thread pool. You can see from the following code that the task entered by the execute method is an instance of the Runnable class.

ThreadsPool.execute (new Runnable () {@ Overridepublic void run () {/ / TODO Auto-generated method stub}})

We can also use the submit method to submit the task, which will return a future, so we can use this future to determine whether the task is executed successfully, and use the get method of future to get the return value. The get method will block until the task is completed, while using the get (long timeout, TimeUnit unit) method will block for a period of time and return immediately. It is possible that the task is not finished.

Try {Object s = future.get ();} catch (InterruptedException e) {/ / handle interrupt exception} catch (ExecutionException e) {/ / handle task exception} finally {/ / close thread pool executor.shutdown ();} thread pool shutdown

We can close the thread pool by calling the shutdown or shutdownNow methods of the thread pool, but they are implemented differently. Shutdown simply sets the state of the thread pool to the SHUTDOWN state, and then interrupts all threads that are not executing the task. The principle of shutdownNow is to traverse the worker threads in the thread pool and then call the thread's interrupt method one by one to interrupt the thread, so a task that cannot respond to the interrupt may never be terminated.

ShutdownNow first sets the state of the thread pool to STOP, then attempts to stop all threads that are executing or pausing the task, and returns the list of waiting tasks.

Whenever either of these two close methods is called, the isShutdown method returns true. When all tasks are closed, the thread pool is closed successfully, and calling the isTerminaed method returns true. Which method we should call to close the thread pool should be determined by the nature of the task submitted to the thread pool. Shutdown is usually called to close the thread pool, or shutdownNow can be called if the task does not have to be finished.

3. Analysis of thread pool

Process analysis: the main workflow of the thread pool is shown below:

As we can see from the figure above, when submitting a new task to the thread pool, the thread pool process is as follows:

1. First of all, the thread pool determines whether the basic thread pool is full. Not full, create a worker thread to execute the task. When it is full, move on to the next process.

two。 Second, the thread pool determines whether the work queue is full? If it is not full, the newly submitted task is stored in the work queue. When it is full, move on to the next process.

3. Finally, the thread pool determines whether the entire thread pool is full. If it is not full, a new worker thread is created to execute the task, and when it is full, it is handed over to the saturation policy to handle the task.

Source code analysis. The above process analysis gives us an intuitive understanding of how the thread pool works, and let's see how it is implemented through the source code. The thread pool performs tasks as follows:

Public void execute (Runnable command) {if (command = = null) throw new NullPointerException (); / / if the number of threads is less than the base number of threads, create the thread and execute the current task if (poolSize > = corePoolSize | |! addIfUnderCorePoolSize (command)) {/ / if the number of threads is greater than or equal to the base number of threads or thread creation fails, put the current task in the work queue. If (runState = = RUNNING & & workQueue.offer (command)) {if (runState! = RUNNING | | poolSize = = 0) ensureQueuedTaskHandled (command);} / / if the thread pool is not running or the task cannot be placed in the queue, and the current number of threads is less than the maximum number of threads allowed, create a thread to execute the task. Else if (! addIfUnderMaximumPoolSize (command)) / / throws a RejectedExecutionException exception reject (command); / / is shutdown or saturated}}

Worker thread. When a thread pool creates a thread, the thread will be encapsulated as a worker thread. After the task is executed, the Worker,Worker will loop indefinitely to get the tasks in the work queue to execute. We can see this in Worker's run method:

Public void run () {try {Runnable task = firstTask; firstTask = null; while (task! = null | | (task = getTask ())! = null) {runTask (task); task = null;}} finally {workerDone (this);}} 4. Reasonable configuration of thread pool

If you want to configure the thread pool reasonably, you must first analyze the characteristics of the task, which can be analyzed from the following angles:

1. The nature of tasks: CPU-intensive tasks, IO-intensive tasks and mixed tasks.

two。 Priority of the task: high, medium and low.

3. The execution time of the task: long, medium and short.

4. Task dependency: whether to rely on other system resources, such as database connections.

Tasks with different nature can be handled separately with thread pools of different sizes. CPU-intensive tasks configure as few threads as possible, such as configuring a thread pool of Ncpu+1 threads. For IO-intensive tasks, because you need to wait for the IO operation, and the thread is not executing the task all the time, configure as many threads as possible, such as 2*Ncpu. If a mixed task can be split, it is divided into a CPU-intensive task and an IO-intensive task. As long as the time difference between the two tasks is not too great, then the throughput of the decomposed task is higher than that of serial execution. If the two tasks are too different in execution time, it is not necessary to decompose them. We can get the number of CPU of 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 high-priority tasks are submitted to the queue all the time, low-priority tasks may never be executed.

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

Rely on the task of database connection pool, because the thread needs to wait for the database to return the result after submitting the SQL. If the longer the waiting time, the longer the idle time of the CPU, then the larger the number of threads should be set, so that you can make better use of CPU.

It is recommended to use bounded queues, which can increase the stability and early warning ability of the system, and can be larger as needed, such as thousands. Once, the queue and thread pool of the background task thread pool used by our group were all full, and the exceptions of abandoning tasks were constantly thrown. Through troubleshooting, it was found that there was a problem with the database, which caused the execution of SQL to become very slow. Because all the tasks in the background task thread pool need to query and insert data from the database, all the worker threads in the thread pool are blocked and the tasks are overstocked in the thread pool. If we had set up an unbounded queue at that time, there would have been more and more queues in the thread pool, which might have filled up memory, making the entire system unavailable, not just background tasks. Of course, all tasks in our system are deployed with separate servers, and we use thread pools of different sizes to run different types of tasks, but this problem can also affect other tasks.

5. Monitoring of thread pool

Monitor through the parameters provided by the thread pool. There are some properties in the thread pool that can be used when monitoring the thread pool

TaskCount: the number of tasks that the thread pool needs to perform.

CompletedTaskCount: the number of tasks completed by the thread pool during operation. Less than or equal to taskCount.

LargestPoolSize: the maximum number of threads ever created by the thread pool. From this data, you can know whether the thread pool is full. If it is equal to the maximum size of the thread pool, it indicates that the thread pool is full.

GetPoolSize: the number of threads in the thread pool. If the thread pool is not destroyed, the threads in the pool will not be destroyed automatically, so this size will only increase.

GetActiveCount: gets the number of active threads.

Monitor by extending the thread pool. By inheriting the thread pool and overriding the thread pool's beforeExecute,afterExecute and terminated methods, we can do something before the task is executed, after execution, and before the thread pool is closed. Such as the average execution time, the maximum execution time and the minimum execution time of monitoring tasks. These methods are empty in the online pool. Such as:

Protected void beforeExecute (Thread t, Runnable r) {} questions about how to analyze and use Java thread pool are shared here. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report