JAVA线程池


本文的出现是为了能够分享个人所学的相关知识,检验自身学习成果。内容会和其他技术存在部分关联,如有任何描述错误或者说明有误的地方,还望各位大佬指出。

1. 了解线程池

线程池简单理解就是一次创建多个线程,当一个任务交由线程池执行时,由线程池交由管理的线程来执行任务。

2. 线程池的优点

(1)不需要主动创建线程,线程的创建和销毁均由线程池管理,减少了不必要的消耗。

(2)提高响应速度,需要线程直接使用,省去了创建时的时间消耗。

(3)更方便于并发管理。

3. JDK中线程池类

说到线程池就需要去了解 Executors ,它是线程池的工厂类,里面对应了四种应用场景的线程池。

3.1 newFixedThreadPool

创建一个线程池,该线程池重用在共享的无边界队列上运行的固定数量的线程。

关键字 固定线程数、无边界阻塞队列

Executor threadPool = Executors.newFixedThreadPool(3);
// 调用
fixedPool.execute(()-> log.info("run with fixedPool"));

3.2 newSingleThreadExecutor

创建一个执行程序,该执行程序使用在不受限制的队列上操作的单个工作线程。

关键字 单个线程、无边界阻塞队列

Executor singlePool = Executors.newSingleThreadExecutor();
// 调用
singlePool.execute(() -> log.info("run with singlePool"));

3.3 newCachedThreadPool

创建一个线程池,该线程池根据需要创建新线程,但是将在先前构造的线程可用时重用它们。通过过期时间进行回收。

关键字 缓存、延迟销毁

Executor cachedPool = Executors.newCachedThreadPool();
// 调用
cachedPool.execute(() -> log.info("run with cachedPool"));

3.4 newScheduledThreadPool

创建一个线程池,该线程池可以安排命令在给定的延迟后运行或定期执行。

关键字 延迟执行、延迟队列

Executor scheduledPool = Executors.newScheduledThreadPool(2);
// 调用
scheduledPool.execute(() -> log.info("run with scheduledPool"));

4. 自定义线程池

如果好奇进去看过JDK定义的四种线程池,我们可以发现都是新建的ThreadPoolExecutor类,通过不同的参数实现不同的场景。

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,  ThreadFactory threadFactory, 
                          RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                Executors.defaultThreadFactory(), handler);
}
参数 含义 作用
corePoolSize 线程池核心线程数 corePoolSize –保留在池中的线程数(即使它们处于空闲状态),除非设置了allowCoreThreadTimeOut
maximumPoolSize 线程池最大线程数 池中允许的最大线程数
keepAliveTime 线程存活时间 当线程数大于内核数时,这是多余的空闲线程将在终止之前等待新任务的最长时间。
unit 线程存活时间单位 keepAliveTime参数的时间单位
workQueue 阻塞队列 用于在执行任务之前保留任务的队列。 此队列将仅保存execute方法提交的Runnable任务。
threadFactory 线程工厂 根据需要创建新线程的对象。
handler 线程池拒绝(饱和)策略 不能由ThreadPoolExecutor执行的任务的处理程序。默认使用AbortPolicy,及抛出异常。
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Slf4j
public class MyThreadPool {
    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 8, 0
            , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(8), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    @Test
    public void testPool() {
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            pool.execute(() -> {
                log.info(String.valueOf(finalI));
            });
        }
    }
}

日志输出如下

JAVA线程池-1.png

  目录