代码使用
public class A implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"开始"); try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
package com.dmg.ds.entity; import java.util.concurrent.*; public class B { public static void main(String[] args) { //获取线程池 ThreadPoolExecutor threadPool=threadPoolExecutor(); for (int i = 0; i <5; i++) { A a=new A(); //执行任务 threadPool.execute(a); int size=threadPool.getQueue().size(); System.out.println("阻塞队列的长度:"+size); System.out.println(); } System.out.println("主线程结束"); } //自定义线程池 7个核心参数 public static ThreadPoolExecutor threadPoolExecutor(){ //核心线程数 int corePoolSize=2; //最大线程数=核心线程数+非核心线程数 int maximumPoolSize=3; //存活时间 时间到了之后 就把这个线程销毁掉 重新创建线程 释放资源 long keepAliveTime=10; //存活时间单位 秒 TimeUnit unit=TimeUnit.SECONDS; //链表阻塞队列 当线程超过核心线程数 那么把任务放入阻塞队列中 排队 BlockingQueue<Runnable> workQueue=new LinkedBlockingQueue<>(1); //默认线程工厂 使用线程工厂来创建线程 ThreadFactory threadFactory=Executors.defaultThreadFactory(); //拒绝策略 RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardPolicy(); return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } }
4种拒绝策略
DiscardPolicy 丢掉当前的任务DiscardOldestPolicy 丢弃队列第一个任务AbortPolicy 抛出异常CallerRunsPolicy 谁调用谁执行
源码分析
内部使用了可重入锁和条件队列,还有一个子类Worker
Worker继承了AQS 实现了Runable接口
在new 对象的时候 会通过线程工厂去创建线程
在执行任务这里
判断已有的线程数据是否大于核心线程数
如果没有大于 那么继续创建线程
如果大于 那么双重检查线程是否是运行中,并把当前线程加入到阻塞队列中
如果创建线程失败 那么执行拒绝策略
在创建工作节点这里
会先进行状态的校验 判断是否是运行中的
然后把runable放入工作节点中 去创建线程
然后通过可重入锁进行加锁,在代码执行完毕 释放锁
然后把创建好的工作节点 放入hashset中
然后执行线程的start方法去启动线程 就会触发run方法
在下面的拒绝策略中,就是又调用了runable的run方法
如果你是mian线程调用,那么触发的拒绝策略就是由main线程执行
在你的A类打印的时候 显示的线程名称就是main
在下面的拒绝策略中 就是抛出了一个异常
在下面的拒绝策略中 就是什么都不管,空方法,也就是丢弃当前的任务
在下面的拒绝策略中,如果线程池还运行着
那么从队列的头部 取出第一个元素,然后删除
然后再使用线程池去执行任务
总结
1.把任务放入线程池,判断当前已创建的线程数是否小于核心线程数
2.如果小于核心线程数,那么创建新的核心线程
3.如果不小于核心线程数,那么把当前任务加入到阻塞队列中
4.如果阻塞队列满了,那么创建非核心线程
5.如果线程数超过了最大线程数+阻塞队列的容量,那么执行拒绝策略