线程池

引入

  1. 线程不仅是Java中的一个对象,每个线程都有自己的工作内存

线程的创建、销毁需要时间,过多的操作会消耗性能
线程过多也会占用内存

  1. 操作系统需要频繁切换上下文,会影响性能
  2. 如果线程 创建时间 + 销毁时间 > 执行任务时间 则不合算。

线程池组成

  1. 线程池管理器
    用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务

  2. 工作线程
    线程池中线程,可以循环的执行任务,在没有任务是处理等待状态

  3. 任务接口
    每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行后的收尾工作,任务执行的状态等

  4. 任务队列
    用于存放没有处理的任务,提供一种缓存机制

典型的ThreadPoolExecutor的创建

	ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
				1,         //核心线程数
				5,     //最大线程数
				5,        //keepAliveTime  ,超过核心线程数的线程,超过keepAliveTime,这个线程湖北销毁
				TimeUnit.SECONDS,  //keepAliveTime 的时间单位
				new LinkedBlockingDeque<Runnable>(5)     //传入边界为5的工作队列

		);

线程池执行时,各创建参数作用流程图

在这里插入图片描述

无解队列与拒绝策略

线程池类的层次结构

队列和拒绝策略API

workQueue队列

  • SynchronousQueue (同步移交队列)
    队列不作为任务的缓冲方式,它不会为队列中元素维护存储空间。可以简单理解为队列长度为零
  • LinkedBlockingQueue (无界队列)
    队列长度不受限制,当请求越来越多时(任务处理速度跟不上任务处理速度,造成请求堆积)可能导致内存占用过多或OOM
  • ArrayBlockintQueue (有界队列)
    队列长度受限,队列满了就会创建多余的线程来执行任务

handler拒绝策略

  • AbortPolicy
    中断抛出异常
  • DiscardPolicy
    默默丢弃任务,不进行任何通知
  • DiscardOldestPolicy
    丢弃掉队列中存在时间最久的任务
  • CallerRunsPolicy
    让提交任务的线程去执行任务(对比前三种谁比较友好)

常见的线程池创建API

  1. Executors 工具类

不知道任务需要多少线程,每需要一个线程就会创建一个线程

  1. newFixedThredPool(int nThreads)

创建一个固定大小、任务队列容量无解的线程池
核心线程数 = 最大线程数
弊端:当请求过多时(任务处理速度跟不上任务提交速度造成请求堆积)可能导致占用过多内存或直接导致OOM异常

ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); 

等同于

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,
                5,
                0,  
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
        );
  1. newCachedThreadPool()

创建的是一个大小无界的缓冲线程池。它的任务队列是一个同步队列。任务加入到池中,如果池中有空闲线程,则用空闲线程,如无则创建新线程执行,池中的线程空闲超过60秒,将被销毁释放。线程数随任务的多少变化
适用于执行时消耗较小的异步任务。池的核心线程数=0,最大线程数=Integer.Max_VALUE
弊端:弊端和newFixedThreadPool一致

ThreadPoolExecutor cachedPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();

等同于

 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                0,           //核心线程数0
                Integer.MAX_VALUE,      //最大线程数是无限大
                60L,
                TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>()
        );
  1. newSigleThreadExecutor()

只有一个线程来执行无界任务队列的单一线程池。该线程池确保任务按加入的顺序一个一个依次执行。当唯一的线程因任务异常中止时,将创建一个新的线程来执行后续的任务。与newFixedThredPool(1)的区别在于,单一线程池的大小在newSigleThreadExecutor方法中硬编码,不能再改变
弊端: 每次来请求直接创建新线程来处理任务,也不使用队列缓冲,会自动回收多余线程,由于将maxPoolSize设置成Integer.MAX_VALUE,当请求很多时就可能创建过多的线程,导致资源耗尽OOM

  1. newScheduledThreadPool(int corePoolSize)

能定时执行任务的线程池。该线程池的核心线程数由参数指定,最大线程数=Integer.MAX_VALUE
弊端:弊端同newCachedThreadPool一致

线程池关闭

  • shutdown()

线程池中无任务时会结束
后续进来的任务会被执行拒绝策略

  • shutdownNow()

线程池中立刻关闭
会返回未进行完毕线程

线程数量

如何确定适合数量的线程

计算型任务

cpu数量的1-2倍

I/O型任务

相对比计算型任务,需多一些线程,要根据具体的IO阻塞时长进行考量决定。也可以考虑根据需要在一个最小数量和最大数量间自动增减线程数
如tomcat中的最大线程数为200

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值