Multithreaded programming learning 11 (detailed explanation of ThreadPoolExecutor)

1、 ThreadPoolExecutor parameter description

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

Tips: generally, we call the threads in the core thread pool as core threads, and these threads will not be recycled; After exceeding the task queue, the created threads are idle threads, and these threads will be recycled (recycling time is keepalivetime)

2、 Introduction to common ThreadPoolExecutor

Executors are factory classes that create ThreadPoolExecutor and scheduledthreadpoolexecutor.

Java provides many types of threadpoolexecutors, such as fixedthreadpool, singlethreadexecution, cachedthreadpool, etc.

FixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
    }

The fixedthreadpool is called a reusable thread pool with a fixed number of threads. You can see that both corepoolsize and maximumpoolsize are set to nthreads; Keepalivetime is set to 0l, which means that redundant idle threads will be terminated immediately; The blocking queue linkedblockingqueue is used as the work queue of the thread (the capacity of the queue is integer. Max_value).

The problem with fixedthreadpool is that the capacity of the queue is integer MAX_ Value can basically be regarded as unbounded, so neither the maximumpoolsize nor keepalivetime parameters will take effect, and the saturated rejection policy will not be executed, resulting in a large number of tasks piling up in the blocking queue.

Fixedthreadpool is applicable to application scenarios where the number of threads needs to be limited in order to meet the requirements of resource management.

SingleThreadExecutor

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1,1,new LinkedBlockingQueue<Runnable>()));
    }

Singlethreadexecution is a thread pool that uses a single thread. You can see that corepoolsize and maximumpoolsize are set to 1, and other parameters are the same as fixedthreadpool, so the risk is the same as fixedthreadpool, so I won't repeat it.

Singlethreadexecution is applicable to tasks that need to be executed in order.

CachedThreadPool

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
    }

Cachedthreadpool is a thread pool that creates new threads as needed. You can see that corepoolsize is set to 0, so all threads created are idle threads; Maximumpoolsize is set to integer MAX_ Value (basically unbounded) means that an unlimited number of idle threads can be created; keepalivetime is set to 60L, which means that the maximum time for idle threads to wait for new tasks is 60 seconds; synchronous queue without capacity is used as the work queue of thread pool.

The problem with cachedthreadpool is that if the main thread submits tasks faster than the threads in maximumpool process tasks, cachedthreadpool will continue to create new threads. In extreme cases, cachedthreadpool will exhaust CPU and memory resources by creating too many threads.

Cachedthreadpool is suitable for small programs that perform many short-term asynchronous tasks, or servers with light load.

3、 Self built ThreadPoolExecutor thread pool

In view of the risks mentioned above, we prefer to use ThreadPoolExecutor to create thread pools instead of executors factory.

The following is a demo instance of ThreadPoolExecutor creating a thread pool:

public class Pool {

    static ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("pool-task-%d").build();
    static ExecutorService executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2,200,new LinkedBlockingQueue<>(1024),threadFactory,new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) throws ExecutionException,InterruptedException {
        // 1. 无返回值的任务执行 -> Runnable
        executor.execute(() -> System.out.println("Hello World"));
        // 2. 有返回值的任务执行 -> Callable
        Future<String> future = executor.submit(() -> "Hello World");
        // get 方法会阻塞线程执行等待返回结果
        String result = future.get();
        System.out.println(result);

        // 3. 监控线程池
        monitor();

        // 4. 关闭线程池
        shutdownAndAwaitTermination();

        monitor();
    }

    private static void monitor() {
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
        System.out.println("【线程池任务】线程池中曾经创建过的最大线程数:" + threadPoolExecutor.getLargestPoolSize());
        System.out.println("【线程池任务】线程池中线程数:" + threadPoolExecutor.getPoolSize());
        System.out.println("【线程池任务】线程池中活动的线程数:" + threadPoolExecutor.getActiveCount());
        System.out.println("【线程池任务】队列中等待执行的任务数:" + threadPoolExecutor.getQueue().size());
        System.out.println("【线程池任务】线程池已执行完任务数:" + threadPoolExecutor.getCompletedTaskCount());
    }

    /**
     * 关闭线程池
     * 1. shutdown、shutdownNow 的原理都是遍历线程池中的工作线程,然后逐个调用线程的 interrupt 方法来中断线程。
     * 2. shutdownNow:将线程池的状态设置成 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。
     * 3. shutdown:将线程池的状态设置成 SHUTDOWN 状态,然后中断所有没有正在执行任务的线程。
     */
    private static void shutdownAndAwaitTermination() {
        // 禁止提交新任务
        executor.shutdown();
        try {
            // 等待现有任务终止
            if (!executor.awaitTermination(60,TimeUnit.SECONDS)) {
                // 取消当前正在执行的任务
                executor.shutdownNow();
                // 等待一段时间让任务响应被取消
                if (!executor.awaitTermination(60,TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            // 如果当前线程也中断,则取消
            executor.shutdownNow();
            // 保留中断状态
            Thread.currentThread().interrupt();
        }
    }
}

To create a thread pool, you need to pay attention to the following points:

4、 Scheduledthreadpoolexecutor

Scheduledthreadpoolexecutor inherits from ThreadPoolExecutor. It is mainly used to run tasks after a given delay, or to execute tasks regularly.

    public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {
        super(corePoolSize,NANOSECONDS,new DelayedWorkQueue(),threadFactory);
    }

The function of scheduledthreadpoolexecutor is similar to that of timer, but it is more powerful and flexible. Timer corresponds to a single background thread, while scheduledthreadpoolexecutor can specify multiple corresponding background threads in the constructor.

Java provides many types of scheduledthreadpoolexecutors, which can be created through executors. The more common ones are scheduledthreadpool, singlethreadscheduledexecurator, etc. It is applicable to application scenarios where multiple background threads are required to execute periodic tasks and the number of background threads needs to be limited to meet the requirements of resource management.

public class ScheduleTaskTest {

    static ThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").build();
    static scheduledexecutorservice scheduledexecutorservice = Executors.newScheduledThreadPool(5,threadFactory);

    public static void main(String[] args) throws ExecutionException,InterruptedException {
        // 1. 延迟 3 秒后执行 Runnable 方法
        scheduledexecutorservice.schedule(() -> System.out.println("Hello World"),3000,TimeUnit.MILLISECONDS);

        // 2. 延迟 3 秒后执行 Callable 方法
        ScheduledFuture<String> scheduledFuture = scheduledexecutorservice.schedule(() -> "Hello ScheduledFuture",TimeUnit.MILLISECONDS);
        System.out.println(scheduledFuture.get());

        // 3. 延迟 1 秒后开始每隔 3 秒周期执行。
        //    如果中间任务遇到异常,则禁止后续执行。
        //    固定的频率来执行某项任务,它不受任务执行时间的影响。到时间,就执行。
        scheduledexecutorservice.scheduleAtFixedRate(() -> System.out.println("Hello ScheduleAtFixedRate"),TimeUnit.MILLISECONDS);

        // 4. 延迟 1 秒后,每个任务结束延迟 3 秒后再执行下个任务。
        //    如果中间任务遇到异常,则禁止后续执行。
        //    受任务执行时间的影响,等待任务执行结束后才开始计算延迟。
        scheduledexecutorservice.scheduleWithFixedDelay(() -> System.out.println("Hello ScheduleWithFixedDelay"),TimeUnit.MILLISECONDS);
    }
}

The execution steps of scheduledthreadpoolexecutor are as follows:

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>