java线程池各方面完美介绍 perfect!!!

线程池是什么?
我的回答:一个池子,水池是放水的,但是这个线程池是放线程的

线程池带来的好处?

  1. 减低资源的消耗。通过重复利用已创建的线程 降低线程创建和销毁造成的消耗
  2. 提高响应的速度,进行任务的快速分配。当任务到达的时候,快速分配线程去执行,任务可以不需要等到线程创建就能立即执行
  3. 提高线程的可管理性。线城市稀缺资源,如果无限创建,不仅会消耗系统资源,还会降低系统的稳定性

常见的池子:数据库连接池、tomcat内部线程池(这两个的内部任务队列都是有界的)

任务提交的过程:

  1. 新任务到达,先判断线程池中的线程数是否达到核心线程数,如果没有达到,则立即创建一个线程用来执行该任务,如果达到啦,向下
  2. 判断任务队列是否已经满啦,如果没有满,将任务放入任务队列等待执行,如果满啦,向下
  3. 判断线程池中的线程是否已经达到线程池最大线程数且都处于工作状态,如果没有达到,则创建一个线程执行该任务,如果没有达到,则交给饱和策略来处理这个任务

在这里插入图片描述

任务提交的4种情况(线程池执行execute方法):

  1. 如果当前运行的线程少于核心线程数corePoolSize,则创建新线程来执行任务(这一执行步骤是要获取全局锁的)
  2. 如果运行的线程数大于等于核心线程数,将任务加入任务队列BlockingQueue
  3. 如果无法将任务加入到任务队列(队列已经满),创建新线程处理任务(需要获取全局锁),这一情况我们可以知道,后面来的任务可能在之前来的任务之前被执行
  4. 如果创建线程超出最大线程数maximumPoolSize,任务被拒绝,并利用饱和策略进行处理

这样设计的原因也是为了在执行execute的方法的时候尽量少获取全局锁

工作线程:

线程池创建线程时,会将线程封装成工作线程Worker,Worker会在执行完任务后,还会循环获取工作队列里的任务来执行

线程池的各个参数分析:

我们通过ThreadPoolExecutor来创建一个线程池:
new ThreadPoolExecutor(
int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时
TimeUnit unit,//时间单位
BlockingQueue<Runnable‘> workQueue,//任务队列,用来储存等待执行任务队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandlerhandler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务);

1、corePoolSize(线程池的基本大小),当提交一个任务到线程池的时候,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能执行新任务也会创建新线程。
2、maximumPoolSize(最大线程数),线程池允许创建的最大的线程数,如果队列满了,并且已经创建的线程数小于最大线程数且都在工作状态,则创建新线程执行任务,(如果任务队列使用了无界的队列这个就没用啦)
3、keepAliveTime(线程活动保持时间),线程池的工作线程空闲的时候,保持存活的时间,所以,如果任务越多,并且每一个任务执行的时间比较短,可以调大这个时间,提高线程的利用率
4、TimeUnit(线程活动保持时间的单位),可选的有(天、小时、分钟、毫秒、微秒、纳秒)
5、workQueue(任务队列),用于保存正在等待的任务的阻塞队列,可以有以下几种进行选择:

  1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列
  2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue;静态工厂方法(Executeors.newFixedThreadPool())使用了这个队列
  3. SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作都要等一个移除操作,不然插入操作一直阻塞
  4. PriorityBlockingQueue:一个具有优先级的无限阻塞队列

6、handler(饱和策略):

AbortPolicy:直接抛出异常,默认的选项
CallrRunsPolicy:只用调用者所在的线程来运行任务
DiscardOldestPolicy:丢弃队列中最近的任务,并执行当前任务
DiscardPolicy:不处理丢弃掉

任务提交

两种方式:execute()、submit()

  1. execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
  2. submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以过 Future 的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

关闭线程池

1、shutdown() :关闭线程池,线程池的状态变为 SHUTDOWN。线程池不再接受新任务了,但是队列里的任务得执行完毕。
2、shutdownNow() :关闭线程池,线程的状态变为
STOP。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的 List。 3、isShutDown 当调用
shutdown() 方法后返回为 true。 4、isTerminated 当调用 shutdown()
方法后,并且所有提交的任务完成后返回为 true

线程池的种类

FixedThreadPool:固定线程数,核心线程数和最大线程数相等
SingleThreadExecutor:单个线程,核心线程数和最大线程数都是1,就是线程数最大不会超过1个
CachedThreadPool:是一个会根据需要创建新线程的线程池。核心线程数为1,最大线程数设置为 MAX,这也就意味着如果主线程提交任务的速度高于 maximumPool 中线程处理任务的速度时,CachedThreadPool 会不断创建新的线程。极端情况下,这样会导致耗尽 cpu 和内存资源
ScheduledThreadPoolExecutor:具有优先级的,这就意味着在任务队列是按照优先级有序排列的

合理的配置线程池

  1. 任务的性质:CPU密集型任务、IO密集型任务、混合型任务
    a.可以利用不同规模的线程池分开处理
  2. 任务的优先级
    使用优先级队列 PriorityBlockingQueue
  3. 任务的执行时间
    利用优先级队列,将时间作为排列标准,时间越短越往前
  4. 任务的依赖性:是否依赖其他系统资源,如数据库连接 因为依赖别的线程,可能会出现等待的情况,所以将线程数设置的大一点,更好的利用CPU
  5. 建议使用有界队列:有界队列可以增加系统的稳定性和预警能力
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值