Java线程池详解

池化设计思想

预设初始资源,不用等用到的时候再创建。

举例:食堂大妈预先打几份菜放着,拿了就能走,不用临时打菜。

应用:线程池、各种连接池。

Java线程池工作流程:

请添加图片描述

创建线程池的几个核心构造参数

// Java线程池的完整构造函数
public ThreadPoolExecutor(
    int corePoolSize, // 线程池的核心线程数,即便是线程池里没有任何任务,也会有corePoolSize个线程在候着等任务
    int maximumPoolSize, // 最大线程数,不管你提交多少任务,线程池里最多工作线程数就是maximumPoolSize
    long keepAliveTime, // 线程的存活时间。当线程池里的线程数大于corePoolSize时,如果等了keepAliveTime时长还没有任务可执行,则线程退出
    TimeUnit unit, //时间单位                                 
    BlockingQueue<Runnable> workQueue, //任务队列。新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务
    ThreadFactory threadFactory, // 线程工厂。定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等。
    RejectedExecutionHandler handler // 拒绝策略,当线程池里线程被耗尽,且队列也满了的时候会调用
)

Java线程池类型

//创建固定核心数的线程池,这里核心数 = 3
ExecutorService executorService = Executors.newFixedThreadPool(3);
//创建单核心的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
//创建一个按照计划规定执行的线程池,这里核心数 = 2
ExecutorService executorService = Executors.newScheduledThreadPool(2);
//创建一个可缓存线程池
ExecutorService executorService = Executors.newCachedThreadPool();

FixedThreadPool 定长线程池

核心线程数和最大线程数相等,keepAliveTime为0(即不生效,不会回收线程)。任务队列为链表结构的无界队列。

SingleThreadExecutor 单线程化线程池

定长线程池线程数为1的情况。

ScheduledThreadPool 定时线程池

核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收,任务队列为延时阻塞队列。

CachedThreadPool 可缓存线程池

无核心线程,非核心线程数量无限,执行完闲置 60s 后回收,任务队列为不存储元素的阻塞队列。

注意:
  • FixedThreadPoolSingleThreadExecutor:主要问题是堆积的请求处理队列均采用 LinkedBlockingQueue,可能会耗费非常大的内存(来任务就进队等待,无界限),甚至 OOM。
  • CachedThreadPoolScheduledThreadPool:主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。

线程池类型及对应队列

线程池实现队列
newFixedThreadPoolLinkedBlockingQueue
newSingleThreadExecutorLinkedBlockingQueue
newScheduledThreadPoolDelayQueue
newCachedThreadPoolSynchronousQueue

队列特点:

LinkedBlockingQueue:基于链表,先进先出,线程安全。
DelayQueue:延时获取元素,无界限(基于二叉树),线程安全。
SynchronousQueue:只存储单个元素(放入元素时要等相应的消费者取走元素),支持先进先出后进先出。

线程池拒绝策略

线程数达到最大值且任务队列已满时,会执行拒绝策略。(任务提交数>maxPoolSize + queueCapacity)

JDK内置四种拒绝策略

AbortPolicy(ThreadPoolExecutor默认):
  • 直接丢弃任务,并抛出RejectedExecutionException异常
CallerRunsPolicy
  • 该任务被线程池拒绝,由调用execute方法的线程执行该任务
DiscardPolicy
  • 直接丢弃任务,什么都不做
DiscardOldestPolicy
  • 抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列
注意:
  • ExecutorService中的线程池实例队列都是无界的,即视OOM也不会出发拒绝策略。

自定义拒绝策略:

  • 通过实现RejectedExecutionHandler接口,自定义一个拒绝策略类,重写它的rejectedExecution()方法:

线程池Demo

 public void testThread() {
        List<String> test = new ArrayList<>();
        int i = 0;
        while (i < 10001) {
            i++;
            test.add(i + "");
        }
        //给List加锁,不加会丢数据
        List<String> thread = Collections.synchronizedList(test);
        //创建线程池
        ExecutorService exec = Executors.newFixedThreadPool(3);
        thread.forEach(u -> {
            exec.execute(() -> {
                System.out.println("线程:"+Thread.currentThread().getName());
                System.out.println("thread:"+u);
            });
        });
        //任务结束关闭线程池
        exec.shutdown();
        //判断线程池是否结束,不加会直接结束方法
        while (true) {
            if (exec.isTerminated()) {
                break;
            }
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值