线程常见的创建方式
1、继承 Thread
2.实现 runable 重写run方法
3.callable(有返回值,且可以跑出异常)
共同点:都是要通过Thread开启 第一种直接.start 后面两种 new Thread(任务实例).start
最后一种就是创建线程池,通过线程池去分配
jdk提供了五种,单个线程池,执行线程数的线程池等等
线程最常用的是ThreadPoolExecutor 可以指定7大特性,来实现线程的管理,分配,及拒绝策略等等。
作用:1.为了解决 频繁创建线程,销毁线程 造成的资源浪费,性能降低
2.方便统一管理
如果不用线程池,也可以用消费者和生成者的方式来控制线程的销毁
主要是利用堵塞队列
例如LinkedBlockingDeque 当队列没有值可以去读取的时候,线程会进入阻塞,通过无限循环的模式,让线程不被销毁,再通过队列进行阻塞
线程池的7大特性
1.核心线程数
2.最大线程数
3.最大存活时间
4.阻塞队列
5.过期时间格式
6.线程工厂
7.拒绝策略
百度解析如下:
(1)corePoolSize:线程池中常驻核心线程数
(2)maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
(3)keepAliveTime:多余的空闲线程存活时间。当前线程池数量超过corePoolSize时,当空闲时间到达keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。
(4)unit:keepAliveTime的时间单位
(5)workQueue:任务队列,被提交但尚未执行的任务
(6)threadFactory:表示生成线程池中的工作线程的线程工厂,用于创建线程,一般为默认线程工厂即可
(7)handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝来请求的Runnable的策略
线程池的工作特性:
刚创建线程的时候,线程池是空的
当提交任务的时候,会判断工作线程数是否小于核心线程
如果小于核心线程,会去创建核心线程,如果大于,工作线程会进入任务队列,也就是阻塞队列
,当继续提交任务的时候,工作线程不小于核心线程,阻塞队列也满了的时候,再去判断当前任务线程是否小于最大线程数,如果小于则会去创建非核心线程
如果大于了最大线程数 则直接拒绝
这个时候核心线程最大,阻塞队列也满了,工作线程还大于设置的最大线程,无法创建非核心线程和核心线程,也无法进入阻塞队列,直接拒绝,可以通过设置过期时间来拒绝等等。
线程池的拒绝策略可见下面链接