1.线程池的引用:
为了提高效率,基于之前的知识:由于进程的创建与销毁所消耗的资源过多,我们便引入了线程,所以如果还想提高效率的话,就需要引入更轻量级的线程------->(协程/纤程),但是这种更加轻量级的线程并没有引入Java的标准库中,所以我们引用不了,所以我们便有了第二种提高效率的方式------>线程池
使用线程池可以降低创建/销毁线程的开销,那么为什么可以降低开销呢?
- 我们事先就可以要使用的线程放到池中,后续可以直接在池中获取,使用完了便还给池
- 从池子中获取/归还线程,是我们用户态可以直接通过代码实现的,并不需要内核态
2.线程池接口类关系图
3.库中定义好的线程池:
在这我们不难看出,线程池对象并不是以我们以前的方式new出来的,而是使用Executors类下的静态方法引出的,而这种方式我们称之为工厂模式,简单解释即为,使用静态方法来替代构造方法来创建对象,其优势就在于当创建很多类型不同的对象时更好地区分明了
//固定池 固定了10个线程 ExecutorService pool1 = Executors.newFixedThreadPool(10); //缓存池 线程数量是动态变化的 任务多了就多几个 ExecutorService pool2 = Executors.newCachedThreadPool(); //类似于定时器 ExecutorService pool3 = Executors.newScheduledThreadPool(3); //单个线程 ExecutorService pool4 = Executors.newSingleThreadExecutor();
4.自定义线程池:
//核心线程数 int coreSize = 1; //最大线程数 int maximum = 3; //线程存活时间 long keepAlive = 10; //线程存活时间单位 TimeUnit unit = TimeUnit.SECONDS; //阻塞队列 BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue(3); //线程工厂 ThreadFactory factory = Executors.defaultThreadFactory(); //拒绝策略 RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ExecutorService myPool = new ThreadPoolExecutor(coreSize,maximum,keepAlive,unit,blockingQueue,factory,handler);
参数解释
核心线程数:类似于公司里的正式员工,可以偶尔的摸鱼
最大线程数:最大线程数 - 核心线程数 = 实习员工 实习员工如果摸鱼,就会被开除
线程存活时间:实习员工摸鱼的最大时间
时间单位 : 定义摸鱼时间的单位的
阻塞队列: 带有阻塞功能存放任务的队列
线程工厂:用于创建线程的
拒绝策略:描述了当线程池任务满了后,继续添加任务会有什么行为
5.四种拒绝策略
- AbortPolicy:默认拒绝策略,拒绝任务,抛出异常
static class myTask implements Runnable{ private int i ; public myTask(int i){ this.i = i; } @Override public void run() { try { //为什么这里要休眠一下才能出现效果:保证每个线程只执行一个任务 //如果不休眠 可能执行的太快了 一个线程会执行几个任务 那么就看不到效果 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行任务:"+i); } } //核心线程数 int coreThread = 1; //最大线程数 int maxThread = 3; //存和时间 long keepAlivetime = 1; //存活时间单位 TimeUnit unit = TimeUnit.SECONDS; //阻塞队列 BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2); //线程工程 ThreadFactory factory = Executors.defaultThreadFactory(); //拒绝策略 RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(coreThread,maxThread,keepAlivetime,unit,queue,factory,handler); //最大任务数 = 最大线程数 + 阻塞队列数 3+2 for(int i = 1; i <= 10; i++){ try{ //也可以使用submit方法 excuete是 poolExecutor.execute(new myTask(i)); }catch (Exception e){ System.out.println("任务:"+i + e.getMessage()); } }
- CallerRunsPolicy:会自动添加多的线程来执行新添的任务
- DiscardPolicy:拒绝任务,不报错
- DiscardOldestPolicy:丢弃阻塞队列中最老的任务,添加任务
//4.DiscardOldestPolicy 任务新增 丢弃阻塞队列中最老的任务 添加到阻塞队列中 //其顺序为: 核心线程数----->阻塞队列------>最大线程数 //1.(核心线程 2.(阻塞队列 3.(阻塞队列 4.(最大线程 5.(最大线程 6.(舍弃2 进入阻塞队列 //7.(舍弃3 进入阻塞队列 8.(舍弃6 进入阻塞队列 9.(舍弃7 进入阻塞队列 //10.(舍弃8 进入阻塞队列 //故最后执行的任务有 1 4 5 9 10