Java进阶13 线程池
Java进阶13 线程池
一、线程生命周期
线程被创建并启动以后,它并不是一启动就进入了执行状态,也不是一直处于执行状态。线程对象在不同的时期有不同的状态,这各种状态就是线程的生命周期。
Java中的线程状态被定义在了java.lang.Thread.State枚举类
状态
含义
NEW(新建)
创建线程对象
RUNNABLE(就绪)
start方法被调用,但是还没有抢到CPU执行权
BLOCKED(阻塞)
线程开始运行,但是没有获取到锁对象
WAITING(等待)
wait方法
TIMED-WAITING(计时等待)
sleep方法
TERMINATED(结束状态)
代码全部运行完毕
1、线程生命周期图
过程:创建(NEW)线程后调用start方法进入就绪(RUNNABLE)状态,如果该线程顺利抢到CPU执行权,就进入运行状态,运行主要执行run方法中的代码逻辑,如果运行期间没有被其他线程夺走CPU执行权,则该线程将一直运行至结束,结束后进入**死亡(TERMINTATED)状态。但如果运行期间被其他线程抢走CPU执行权,该线程将回到就绪状态。此外,当其运行期间调用了sleep()方法,则会进入即计时等待(TIMED-WAITING)状态 ,指定的休眠时间到达后,自动转为就绪状态;如果调用了wait()方法,就会进入无限等待(WAITING)状态,需要其他线程调用notify()方法才能继续进入就绪状态;如果在运行期间无法获取到锁,就会进入阻塞(BLOCKED)**状态,知道其他线程释放了锁,该线程才能获得锁,获得锁之后就会进入就绪状态。
二、线程池
将线程对象交给线程池维护,可以降低系统成本,从而提升程序的性能
2、使用JDK提供的线程池
方法
说明
static ExecutorService newCachedThreadPool()
创建一个默认的线程池
static newFixedThreadPool(int nThreads)
创建一个指定最多线程数量的线程池
3、自定义线程池
ThreadPoolExecutor类
3.1 构造方法
ThreadPoolExecutor(int corePoolSize,int maxnumPoolSize,long keepActiveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
参数1:核心线程数量【不能小于0】
参数2:最大线程数量(核心线程数+临时线程数)【不能小于等于0】
参数3:空闲时间(数值)【不能小于0】
参数4:时间单位【时间单位】
参数5:任务队列【不能为null】
有限队列 new ArrayBlockingQueue<>(队列长度)
无限队列 new LinkedBlockingQueue<>()
参数6:线程对象任务工厂【不能为null】
参数7:拒绝策略【不能为null】
3.2 Demo
public class ThreadPoolDemo2 {
? ?public static void main(String[] args) {
? ? ? ?/*
? ? ? ? ? ?指定核心线程数为2,最大线程数为5,空闲时间为60秒,有限队列,线程任务工厂为指定默认的工厂,拒绝策略为AbortPolicy的自定义线程池;
? ? ? ?*/
? ? ? ?ThreadPoolExecutor pool = new ThreadPoolExecutor(
? ? ? ? ? ? ? ?2,
? ? ? ? ? ? ? ?5,
? ? ? ? ? ? ? ?60,
? ? ? ? ? ? ? ?TimeUnit.SECONDS,
? ? ? ? ? ? ? ?new ArrayBlockingQueue<>(10),
? ? ? ? ? ? ? ?Executors.defaultThreadFactory(),
? ? ? ? ? ? ? ?new ThreadPoolExecutor.AbortPolicy()
? ? ? );
?
? ? ? ?for (int i = 1; i <= 16; i++) {
? ? ? ? ? ?pool.submit(new Runnable() {
? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ?public void run() {
? ? ? ? ? ? ? ? ? ?System.out.println(Thread.currentThread().getName()+"提交了线程任务");
? ? ? ? ? ? ? }
? ? ? ? ? });
? ? ? }
? }
}
3.3 注意事项
-
Q:临时线程对象何时创建?
A:提交的线程任务数量 > 核心线程数 + 任务队列数量
-
Q:什么时候会触发拒绝策略?
A:提交的线程任务数量 > 最大线程数 + 任务队列数量
3.4 拒绝策略
策略选项
说明
ThreadPoolExecutor.AbortPolicy
丢弃任务并抛出RejectedExecutionException异常(默认)
ThreadPoolExecutor.DiscardPolicy
丢弃任务,但是不抛出异常,这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy
抛弃队列中等待最久的任务,然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunPolicy
调用任务的run()方法,绕过线程池直接执行
三、单例设计模式
单例指单个实例,保证类的对象在内存中只有一份
1、使用场景
如果创建一个对象需要消耗的资源过多,比如I/O与数据库的连接,并且这个对象完全是可以复用的,我们就可以考虑将其设计为单例的对象
2、设计模式
2.1 饿汉式
class Single {
? ?
? ? //1、私有构造方法,组织其他类创建本类对象
? ?private Single(){
? }
?
? ?//在本类中创建自己这个类的对象
? ?private static Single s = new Single();
?
?
? ?/**
? ? * 提供一个方法供外部获取本类单例对象
? ? * @return 返回单例对象
? ? */
? ?public static Single getInstance(){
? ? ? ?return s;
? }
}
2.2 懒汉式(延迟加载模式)
class Single { ? ? ? ? //1、私有构造方法,组织其他类创建本类对象 ? ?private Single(){ ? } ? ? ?//在本类中创建自己这个类的对象 ? ?private static Single s = new Single(); ? ? ? ?/** ? ? * 提供一个方法供外部获取本类单例对象 ? ? * @return 返回单例对象 ? ? */ ? ?public static Single getInstance(){ ? ? ? ?return s; ? } }
- 注意事项:双重检查锁是可以减少上锁次数,避免创建出多个对象造成效率浪费