Thread pool in-depth understanding

Source: Internet
Author: User
Tags constructor sleep

benefits of using a thread pool

The rational use of the thread pool can bring three benefits. First: Reduce resource consumption. Reduce the consumption caused by thread creation and destruction by reusing the threads that have been created. Second: Improve response speed. When a task arrives, the task can be executed without the need to wait for the thread to be created. Third: Improve the manageability of threads. Threads are scarce resources that, if created indefinitely, not only consume system resources, but also reduce system stability, using a thread pool for uniform allocation, tuning, and monitoring.

two scenarios where the thread pool is used

To properly configure the thread pool, you must first analyze the task characteristics, which can be analyzed from the following angles:

1. Nature of tasks: CPU-intensive tasks, IO-intensive tasks, and hybrid tasks.

2. Priority of tasks: high, medium and low.

3. Task execution time: long, medium and short.

4. Dependencies on tasks: whether to rely on other system resources, such as database connections.

Tasks of a different nature can be handled separately by thread pools of different sizes. CPU-intensive tasks are configured with as few threads as possible, such as configuring thread pooling for ncpu+1 threads. IO-intensive tasks are not always performing tasks because of the need to wait for IO operations, and the configuration of as many threads as possible (most of the time for database write operations is on Io, so it takes a lot of time to wait for the results after the data is submitted.) You should configure a more capable thread at this time, such as 2*NCPU. Mixed-type tasks, if they can be split into a CPU-intensive task and an IO-intensive task, as long as the time difference between the two tasks is not too large, then the throughput rate after decomposition is higher than the serial execution throughput rate, if the two task execution time is too large, it is not necessary to decompose. We can get the number of CPUs for the current device through the Runtime.getruntime (). Availableprocessors () method.

Tasks with different priority levels can be handled using the priority queue Priorityblockingqueue. It allows high-priority tasks to be executed first, and it is important to note that low-priority tasks may never be executed if a task with a high priority is committed to the queue.

Tasks with different execution times can be handled by different sizes of thread pools, or priority queues can be used to perform tasks that have a short execution time.

A task that relies on the database connection pool, because the thread submits the SQL and waits for the database to return the results, and the longer the CPU idle time waits, the greater the number of threads should be, so that the CPU can be better utilized.

It is recommended to use bounded queue , the bounded queue can increase the stability and early warning ability of the system, can be set to a larger point, such as thousands of. One time the queue and thread pool of the background task thread pool used by our group were full, and threw out the exception of the task, and by finding out that there was a problem with the database, the execution of SQL became very slow, because the tasks of the background task line constructor all needed to query and insert data into the database. So the work thread that causes the line constructor all blocks, the task backlog is constructor online. If we were to set up the unbounded queue, the thread pool would have more and more queues, potentially filling up the memory, making the whole system unusable, not just a background task. Of course all our system tasks 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. Of course, we can also write a monitoring program, the amount of data that has not yet been written to the database and cached in the work queue, and the dynamic sleep method to reduce the pressure to write to the database, see the Multi-threaded batch to the database to insert data item Links:

Http://pan.baidu.com/s/1eQEkfZG

Three- thread pool principle


We can create a thread pool through threadpoolexecutor. To create a thread pool, you need to enter a few parameters:

Newthreadpoolexecutor (Corepoolsize, Maximumpoolsize,

Keepalivetime,milliseconds,runnabletaskqueue, Threadfactory,handler);

Corepoolsize (the base size of the thread pool in the core thread pool in the figure above): When a task is submitted to the thread pool, the line pool creates a thread to perform the task, even if other idle basic threads are able to perform new tasks, Wait until the number of tasks that need to be executed is greater than the thread pool base size. If the thread pool's Prestartallcorethreads method is called, the thread pool creates and starts all basic threads in advance.

· Runnabletaskqueue (the Workqueue task queue in the previous illustration): A blocking queue that holds tasks waiting to be executed. You can select the following blocking queues.

1. Arrayblockingqueue: is a bounded blocking queue based on the array structure, which sorts the elements by FIFO (first in, out) principle.

2. Linkedblockingqueue: A linked-list-based blocking queue in which the queue is sorted by FIFO (first-out), with throughput typically higher 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 for another thread to invoke the remove operation, or the insert operation will always be in a blocked state, with throughput typically higher than linkedblockingqueue, and the static factory method Executors.newcachedthreadpool Use this queue.

4. Priorityblockingqueue: an infinite blocking queue with priority.

· Maximumpoolsize (maximum thread pool size): The maximum number of threads allowed to be created by a thread pool. If the queue is full and the number of threads that have been created is less than the maximum number of threads, the thread pool will then create new threads to perform the task. It is worth noting that if you use the unbounded task queue This parameter has little effect.

As we can see from the above diagram, when a new task is submitted to the thread pool, the thread pool processes the following:

1. First the thread pool determines whether the base thread pool is full. Not full, create a worker thread to perform the task. Full, then go to the next process.

2. Next, the thread pool determines whether the task queue is full. is not full, the newly submitted task is stored in the work queue. Full, then go to the next process.

3. The last thread pool determines whether the entire thread pool is full. is not full, a new worker thread is created to perform the task, and the saturation policy is assigned to handle the task.

Processing flow

To illustrate:

Assuming that Coresize is set to 4,maximumpoolsize set to 6, the Task force is listed as bounded queue workequeque its size is 3. If there are no tasks in the thread pool at this point, the task waiting for the insert to execute is t1,t2,t3,t4,t5,t6,t7,t8....tn. The throttling conditions are long for each task T execution time.

Since Coresize is 4, from T1 to T4 there is no need to wait for the direct creation of 4 threads to begin execution. Wait until T5 enter time, because Coresize is full, but Workqueque still have three positions empty, then T5 into Workqueque, similarly t6,t7 also enter the queue waiting. At this point the task T8 enter,

At this point the status is (1) coresize is full

(2) Worqueue is full

(3) maximumpoolsize-coresize=2 (there are two locations, you can create a new thread)

However, the number of threads in the thread pool has not reached the maximum of 6 (4 threads are currently running on the thread pools), so the thread pooling creates a new thread for T8. There is a situation where the T8 enters the thread pool longer than T5, T6, T7, but T8 is preceded by the wait in Workqueue (T5, T6, T7) to execute

Same T9 came over the state after

At this point the status is (1) coresize is full

(2) Worqueue is full

(3) maximumpoolsize-coresize=2 (T8 Open the thread, there is a location, you can create a new thread) T9 will be executed first.

When T10 came over, I found

(1) Coresize is full

(2) Worqueue is full

(3) maximumpoolsize-coresize=2 (T8, T9 opens a thread with 0 positions and cannot create a new thread) T10 is rejected by the thread pool. We can implement the Rejectedexecutionhandler interface ourselves, as shown below. Our interface is automatically called when the task is rejected.

Package com.journaldev.threadpool;
Import Java.util.concurrent.RejectedExecutionHandler;
Import Java.util.concurrent.ThreadPoolExecutor;
 
public class Rejectedexecutionhandlerimpl implements Rejectedexecutionhandler {public
 
    void rejectedexecution ( Runnable R, Threadpoolexecutor executor) {
        System.out.println (r.tostring () + "is rejected");
    }
 
} 

· Threadfactory: Used to set the factory for creating threads, you can set a more meaningful name for each thread that is created through the thread factory, and it is very helpful to debug and locate problems.

Rejectedexecutionhandler (Saturation policy): When the queue and thread pool are full, indicating that the thread pools are saturated, a policy must be taken to handle the new tasks that are submitted. This policy is abortpolicy by default, indicating that an exception is thrown when a new task cannot be processed. The following are the four strategies provided by JDK1.5. N AbortPolicy: Throws an exception directly.

1. Callerrunspolicy: Run the task only with the caller's thread.

2. Discardoldestpolicy: Discards the most recent task in the queue and executes the current task.

3. Discardpolicy: Do not Dispose, discard.

4. It is also possible to implement the Rejectedexecutionhandler interface customization policy according to the application scenario. Tasks such as logging or persistence that cannot be processed.

· KeepAliveTime (thread activity hold time): When the worker thread of the thread pool is idle, the time to remain alive. So if the task is a lot, and each task executes a short time, you can adjust the time to increase the utilization of the thread.

· Timeunit (unit of thread activity hold time): Optional units have day (days), hours (HOURS), minutes (MINUTES), milliseconds (MILLISECONDS), microseconds (microseconds, 1 per thousand milliseconds), and nanoseconds ( nanoseconds, 1 per thousand microseconds).

thread pool monitoring methods

monitored by the parameters provided by the thread pool . Line constructor Some properties can be used when monitoring the thread pool

· Taskcount: The number of tasks that the thread pool needs to perform (as long as the tasks accepted by the thread pools are counted).

· 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. Equal to the maximum size of the thread pool means that the thread pool was once full.

· Getpoolsize: The number of threads in the thread pool. Even after all tasks have been completed, the thread will continue to survive for some time, depending on the timeunit (the unit of thread activity hold time).

· Getactivecount: Gets the number of active threads.

Four Code learning examples

1) Task class waiting to run

Package com.journaldev.threadpool;

public class Workerthread implements Runnable {

    private String command;

    Public Workerthread (String s) {
        this.command=s;
    }

    public void Run () {
        System.out.println (Thread.CurrentThread (). GetName () + "Start. Command = "+command");
        ProcessCommand ();
        System.out.println (Thread.CurrentThread (). GetName () + "End.");

    private void ProcessCommand () {
        try {
            thread.sleep ()
        } catch (Interruptedexception e) {
            E.printstacktrace ();
        }
    }

    @Override public
    String toString () {
        return ("Thread:" +this.command);
    }
}
2) We create a test thread to create a thread pool from the executors framework.

Package com.journaldev.threadpool;

Import Java.util.concurrent.ExecutorService;
Import java.util.concurrent.Executors;
Import Java.util.concurrent.TimeUnit;

public class Simplethreadpool {public

    static void Main (string[] args) {
        Executorservice executor = executors.new Fixedthreadpool (5);
        for (int i = 0; i < i++) {
            Runnable worker = new Workerthread ("" + i);
            Executor.execute (worker);
            System.out.println ("Worker" +i+ "added");
            There is no blocking of the top five tasks directly into the thread pool to open threads after the execution of the five task join Work queue wait for execution
          }
        executor.shutdown ();
        try {
			while (!executor.awaittermination (1, timeunit.seconds))
			{}
		} catch (Interruptedexception e) {
			//TODO auto-generated catch block
			e.printstacktrace ();
		}
       /* while (!executor.isterminated ()) {
        }//loops until all tasks are completed
*/        System.out.println ("Finished all Threads");
    }

}

3) Here is an example of a custom implementation of the Rejectedexecutionhandler interface:

Package com.journaldev.threadpool;
 
Import Java.util.concurrent.RejectedExecutionHandler;
Import Java.util.concurrent.ThreadPoolExecutor;
 
public class Rejectedexecutionhandlerimpl implements Rejectedexecutionhandler {public
 
    void rejectedexecution ( Runnable R, Threadpoolexecutor executor) {
        System.out.println (r.tostring () + "is rejected");
    }
 
}

4) Threadpoolexecutor provides several ways to use it to find out the current state of the performer, pool size, number of active threads, and number of tasks. So, I have a monitor thread, which will print the information of the performer at a certain interval of time.

Package com.journaldev.threadpool;
 
Import Java.util.concurrent.ThreadPoolExecutor;
 
    public class Mymonitorthread implements Runnable {private Threadpoolexecutor executor;
 
    private int seconds;
 
    Private Boolean run=true;
        Public Mymonitorthread (threadpoolexecutor executor, int delay) {this.executor = executor;
    This.seconds=delay;
    } public void Shutdown () {this.run=false; The public void Run () {System.out.println (run) {String.Format ( "[Monitor] [%d/%d] Active:%d, completed:%d, Task:%d, IsShutDown:%s, isterminated:%s", This.ex
                        Ecutor.getpoolsize (),//number of threads held in thread pool this.executor.getCorePoolSize (),//thread pool base size
                        This.executor.getActiveCount (),//current active thread size this.executor.getCompletedTaskCount (),//number of tasks completed
             This.executor.getTaskCount (),//Total tasks           This.executor.isShutdown (),//Whether it has been closed (no longer accepting new tasks) this.executor.isTerminated ()));//Whether All tasks are completed
                As long as the try {thread.sleep (seconds*1000) is saved;
                } catch (Interruptedexception e) {e.printstacktrace (); }
        }
 
    }
}

5) Here is an example of implementing a thread pool using a thread pool:

Package com.journaldev.threadpool;
Import Java.util.concurrent.ArrayBlockingQueue;
Import java.util.concurrent.Executors;
Import Java.util.concurrent.ThreadFactory;
Import Java.util.concurrent.ThreadPoolExecutor;
 
Import Java.util.concurrent.TimeUnit; public class Workerpool {public static void main (String args[]) throws interruptedexception{//rejectedexec
        Utionhandler implementation Rejectedexecutionhandlerimpl Rejectionhandler = new Rejectedexecutionhandlerimpl (); Get the Threadfactory implementation to use threadfactory Threadfactory = Executors.defaultthreadfactory (
        ); Creating the Threadpoolexecutor threadpoolexecutor Executorpool = new Threadpoolexecutor (2, 4, ten, Timeunit.seco
        NDS, New arrayblockingqueue<runnable> (2), threadfactory, Rejectionhandler);
        Start the monitoring thread mymonitorthread monitor = new Mymonitorthread (Executorpool, 3);
   Thread monitorthread = new thread (monitor);     Monitorthread.start (); Submit work to the thread pool for (int i=0; i<10; i++) {Executorpool.execute (new workerthread ("cm
        D "+i)); } executorpool.shutdown ();//execute this method immediately, be sure to add this sentence, otherwise you will assume that the thread pool will also have a new task/*shutdown method: (1) Set the thread pool to shutdown state (2) interrupt There are no threads executing the task (because threads in the thread pool maintain a number of threads active, breaking threads that are not performing tasks means shutting down idle threads) (3) The thread pool can no longer accept new tasks, but waits for tasks that have been added to the work queue to complete. *///Executorpool.awaittermination (1, timeunit.seconds) will always be false try {//every second to detect if the thread pool is complete all tasks can also use while (!execut Or.isterminated ()) while (!executorpool.awaittermination (1, timeunit.seconds)) {}} catch (Interruptedexception e) {
E.printstacktrace ();} }


</pre><pre>
Execution Result:

Pool-1-thread-1 Start. Command = cmd0
pool-1-thread-2 Start. Command = cmd1
thread: CMD6 is rejected
thread: CMD7 is rejected
thread: Cmd8 is rejected
pool-1-thread-4 Start. Command = cmd5
pool-1-thread-3 Start. Command = CMD4
thread: CMD9 is rejected
[monitor] [0/2] active:2, completed:0, Task:4, Isshutdown:false, Isterminat Ed:false
[Monitor] [4/2] active:4, completed:0, Task:6, Isshutdown:true, Isterminated:false
pool-1-thread-1 End.
Pool-1-thread-2 End.
Pool-1-thread-1 Start. Command = cmd2
pool-1-thread-2 Start. Command = cmd3
pool-1-thread-4 End.
Pool-1-thread-3 End.
[Monitor] [2/2] Active:2, Completed:4, Task:6, Isshutdown:true, Isterminated:false
[Monitor] [2/2] active:2, Completed:4, Task : 6, Isshutdown:true, Isterminated:false
pool-1-thread-2 End.
Pool-1-thread-1 End.
[Monitor] [0/2] active:0, Completed:6, Task:6, Isshutdown:true, isterminated:true


For specific reasons, refer to the thread pool process example above. Test Project source code download link

http://pan.baidu.com/s/1dK666



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.