Concurrent programming series blog
The original link
Concurrent programming Series: How to use thread pools correctly? In the previous chapter, we learned the basics of threads, and this blog will continue to learn about thread pools in multithreading
1. Is more threads better?
Before learning about multithreading, the reader might wonder, okay? If a single thread is too slow, can more threads be created to run the task? In the case of concurrency, is the creation of as many threads as possible? This is a classic problem, draw a picture of creating a lot of threads, and then analyze the situation.
- Both thread creation and thread destruction take time, and the creation time + destruction time > task execution time is not cost-effective
- The default stack size for a Thread is 1M, and this stack space needs to be allocated from system memory. Therefore, the more threads, the more memory is needed
- The operating system requires frequent thread context switching, so creating too many threads will affect performance
Context switch: For single core CPU, in one moment can only run a single thread, for parallel CPU also can support multithreaded code is executed, the CPU is through to allocate a time slice to solve the thread, the so-called time slice is assigned to each thread CPU time, time slice of time is very short, so after completing a time slice, Before switching tasks, save the state of the task so that it can be loaded when switching back next time. Therefore, the process from saving the state of the task to reloading the task is called context switching. Context switching can be performed not only between threads, but also between processes
2. How to use multithreading correctly?
- If it’s a computational task?
One to two times the number of cpus
- If it’s IO intensive?
More threads are needed, depending on the specific I/O blocking duration
How Java thread pools work
- Receives the task and puts it into the task repository of the thread pool
- The worker thread fetches from the task repository in the thread pool and executes
- The thread blocks when there is no task and wakes up when there is one
4. Master JUC thread pool API
- Executor: Interface class
- ExecutorService: Adds shutdown methods and support for Runnable, Callable, and Future
* shutdownNow: Execute completed, return future execution * awaitTermination: block waiting for task closure to complete * submit: Both submit tasks and support Runnable and Callable * invokeAll: Perform all tasks in the collectionCopy the code
- ScheduleExecutorService: Added support for scheduled tasks
Among themschedule(Runablle , long, Timeunit)
andschedule(Callable<V> , long, TimeUnit)
It’s how long it takes to execute, andscheduleAtFixedRate
Methods andscheduleWithFixedDelay
Methods represent periodic repetitions
To describescheduleAtFixedRate
Methods andscheduleWithFixedDelay
Differences in methods:scheduleAtFixedRate
: Perform tasks repeatedly at a fixed time frequency, for example, every 10s. That is, two tasks are executed at a fixed interval regardless of whether the tasks are completed
ScheduleWithFixedDelay: Repeated execution of tasks with a fixed task time delay. This task is completed no matter how long the task is executed, and then the next task is executed at a predetermined interval of 3s. The interval between each task is the same
-
Executors: Quickly get the thread pool tool class and create the thread pool factory class
newFixedThreadPool(int nThreads)
: Creates a thread pool of fixed size with unbounded task queues. Number of core threads in the thread pool = Maximum thread pool =nThreadsnewCachedThreadPool()
: Creates an unbounded buffer thread pool. Its task queue is a synchronization queue. If there are free threads in the queue, they are used for execution; if not, a new thread is created for execution. Threads in the pool that are idle for more than 60 seconds are released. Buffer thread pools are used to perform asynchronous tasks that take a small amount of time. The number of core threads in the thread pool =0, and the maximum thread pool =Integer.MAX_VALUE
newSingleThreadExecutor()
: Creates a single thread pool with only one thread to execute an unbounded task queue. This thread pool executes tasks one by one in order, with only one thread executing at any one time. Single thread pool andnewFixedThreadPool(1)
The difference is that the pool size of a single thread pool cannot be changednewScheduleThreadPool(int corePoolSize)
: A thread pool that can execute tasks on time. The number of core threads in the pool is specified by the parametercorePoolSize
Specifies that the maximum number of threads =Integer.MAX_VALUE
newWorkStealingPool()
: created with the number of processors currently available on the system as the parallel levelwork-stealing thread pool(ForkJoinPool)
newWorkStealingPool(int parallelism)
: specifiedparallelism
Created at the parallel levelwork-stealing thread pool(ForkJoinPool)
-
ThreadPoolExecutor: Standard implementation of thread pools
The main parameters of ThreadPoolExecutor are listed below:
parameter | describe |
---|---|
corePoolSize | Number of core threads |
maxPoolSize | Maximum number of threads |
KeepAliveTime + Time unit | The lifetime of idle threads |
ThreadFactory | Thread factory, used to create threads |
workQueue | A queue for storing tasks can be called a work queue |
Handler | Used to process rejected tasks |
* * * is very convenient to use, but the following excerpted from the Ali programming specification manual emphasizes careful use of Executors to create thread pools:
Thread pools don’t allow to be created by Executors. Use ThreadPoolExecutor instead.
In this way, students can be more clear about the running rules of the thread pool and avoid the risk of resource exhaustion. Executors each method disadvantages:
1) newFixedThreadPool and newSingleThreadExecutor:
The main problem is that the stacked request processing queue can consume a lot of memory, or even OOM.
2) newCachedThreadPool and newScheduledThreadPool: The main problem is that the maximum number of threads is integer. MAX_VALUE, which may create a very large number of threads, or even OOM.
Basic parameters of ThreadPoolExecutor:
new ThreadPoolExecutor(
2.// Number of core threads
5.// Maximum number of threads
60L.// keepAliveTime. If the thread is idle beyond this value, it is destroyed and freed
TimeUnit.SECONDS, // keepAliveTime Time unit
new ArrayBlockingQueue(5)); // Pass the work queue with boundary 5
Copy the code
The core parameters of the thread pool are corePoolSize, maxPoolSize, and workQueue.Schematic diagram of how a thread pool works: Tasks can be dropped until the thread pool is full, then rejected, and all threads except the core thread are properly reclaimed. So normally, the number of threads in the thread pool will be in the closed range between corePoolSize and maximumPoolSizeBasic instance of ThreadPoolExecutor:
ExecutorService service = new ThreadPoolExecutor(2.5.60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(5));
service.execute(() ->{
System.out.println(String.format("thread name:%s",Thread.currentThread().getName()));
});
// To avoid memory leaks, remember to close the thread pool
service.shutdown();
Copy the code
Examples of ThreadPoolExecutor plus Callable and Future use:
public static void main(String[] args) {
ExecutorService service = new ThreadPoolExecutor(2.5.60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(5));
Future<Integer> future = service.submit(new CallableTask());
Thread.sleep(3000);
System.out.println("future is done?" + future.isDone());
if (future.isDone()) {
System.out.println("CallableTask returns parameter :"+future.get());
}
service.shutdown();
}
static class CallableTask implements Callable<Integer>{
@Override
public Integer call(a) {
return ThreadLocalRandom.current().ints(0, (99 + 1)).limit(1).findFirst().getAsInt(); }}Copy the code