1、ThreadPoolExecutor

1)线程池状态

ThreadPoolExecutor使用int的高3位来表示线程池状态,低29位表示线程数量

1.线程池的五种状态,只能由小到大迁移,即-1>0>1>2>3。

2.shutdown(不清空任务队列、 会等它们完成,shutdownNow)会清 空任务队列、不等它们完成。shutdown()只中断空闲的线程,shutdownNow()会 中断所有的线程,不管你执行没执行完。

3.TIDYING 和TREMINATED二者之间执行了一个钩子函数terminated(,目前这是-个空的实现。

为了保证线程状态和线程数量赋值操作的原子性,所以将两者存储在同一个原理变量中,用一次cas操作进行赋值

2)构造方法


public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
  • corePoolSize 核心线程数目(最多保留的线程数)
  • maximumPoolSize 最大线程数目
  • keepAliveTime 生存时间-针对救急线程
  • unit 时间单位-针对救急线程
  • workQueue 阻塞队列
  • threadFactory 线程工厂- 可以为线程创建时起个好名字
  • handler 拒绝策略

工作方式

核心线程和救急线程都是懒惰式创建,节约资源,使用的时候才创建

当核心线程都在执行任务,会将新加入的任务梵高阻塞队列中,当阻塞队列也满了,才会使用救急线程

  • 救急线程和核心线程的区别就是,救济线程有生存时间,当任务执行完之后,在生存时间之内没有任务再执行,救急线程就会被销毁。

  • 当救急线程也不够用于执行任务时,才会使用拒绝策略。当队列选择的是有界队列时,那么任务超过了队列大小才会创建救急线程

  • 如果线程到达maximumPoolSize仍然有新任务这时会执行拒绝策略。拒绝策略jdk提供了4种实现,其它著名框架也提供了实现

    • AbortPolicy 让调用者抛出RejectedExecutionException异常,这是默认策略

    • CallerRunsPolicy 让调用者运行任务

    • DiscardPolicy 放弃本次任务

    • DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之

    • Dubbo 的实现,在抛出RejectedExecutionException异常之前会记录日志,并dump线程栈信息,方便定位问题

    • Netty 的实现,是创建一个新线程来执行任务

    • ActiveMQ的实现,带超时等待(60s) 尝试放入队列,类似我们之前自定义的拒绝策略

    • PinPoint 的实现,它使用了一个拒绝策略链,会逐一尝试策略链中每种拒绝策略

      当高峰过去后,超过corePoolSize 的救急线程如果- -段时间没有任务做,需要结束节省资源,这个时间由keepAliveTime和unit来控制。

Executors

1)newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}

特点

  • 核心线程数最大线程数(没有救急线程被创建),因此也无需超时时间

  • 阻塞队列是无界的,可以放任意数量的任务

    评价
    适用于任务量已知,相对耗时的任务

代码:


public static void main(String[] args) {ExecutorService pool= Executors.newFixedThreadPool(2);pool.execute(()->{System.out.println(Thread.currentThread()+"1");});pool.execute(()->{System.out.println(Thread.currentThread()+"2");});pool.execute(()->{System.out.println(Thread.currentThread()+"3");});}

不会随着主线程的结束而结束

自定义线程工厂–用于命名线程名字

 public static void main(String[] args) {ExecutorService pool= Executors.newFixedThreadPool(2, new ThreadFactory() {private AtomicInteger t=new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {return new Thread(r,"mypool_t"+t.getAndIncrement());}});pool.execute(()->{System.out.println(Thread.currentThread()+"1");});pool.execute(()->{System.out.println(Thread.currentThread()+"2");});pool.execute(()->{System.out.println(Thread.currentThread()+"3");});}

2)newCacheThreadPool

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}

特点

  • 核心线程数是0,最大线程数是Integer.MAX_ VALUE,救急线程的空闲生存时间是60s, 意味着

    • 全部都是救急线程(60s 后可以回收)
    • 救急线程可以无限创建
  • 队列采用了SynchronousQueue 实现特点是,它没有容量,没有线程来取是放不进去的(- 手交钱、- -手交货)

评价
整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲1分钟后释放线程。
适合任务数比较密集,但每个任务执行时间较短的情况

3)newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}

使用场景:
希望多个任务排队执行。线程数固定为1,任务数多于1时,会放入无界队列排队。任务执行完毕,这唯一的线程也不会被释放。

区别:

  • 自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池还会新建-个线程,保证池的正常工作
  • Executors.newSingleThreadExecutor() 线程个数始终为1,不能修改
    • FinalizableDelegatedExecutorService 应用的是装饰器模式,只对外暴露了ExecutorService 接口,因此不能调用ThreadPoolExecutor中特有的方法
  • Executors.newFixedThreadPool(1)初始时为1,以后还可以修改
    • 对外暴露的是ThreadPoolExecutor对象,可以强转后调用setCorePoolSize 等方法进行修改

提交任务

Callable比Runnable多了返回值,Runnable也不能抛出异常

代码1:

package demo1;import java.util.concurrent.*;public class TestSumbit {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService pool = Executors.newFixedThreadPool(2);Future<String> future=pool.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("running");Thread.sleep(1000);return "ok";}});System.out.println(future.get());}
}

代码2:

package demo1;import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;public class TestSumbit {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService pool = Executors.newFixedThreadPool(2);/*Future<String> future=pool.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println("running");Thread.sleep(1000);return "ok";}});*/List<Future<Object>> futures = pool.invokeAll(Arrays.asList(() ->{System.out.println(Thread.currentThread() + "begin");Thread.sleep(1000);return "1";},() ->{System.out.println(Thread.currentThread() + "begin");Thread.sleep(500);return "2";},() ->{System.out.println(Thread.currentThread() + "begin");Thread.sleep(2000);return "3";}));futures.forEach(f->{try {System.out.println(Thread.currentThread()+" "+f.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}});//System.out.println(future.get());}
}

关闭线程

shutdown

线程池状态变为SHUTDOWN
1、不会接收新任务
2、但已提交任务会执行完
3、此方法不会阻塞调用线程的执行

shutdownNow

线程池状态变为STOP
1、不会接收新任务
2、会将队列中的任务返回
3、并用interrupt 的方式中断正在执行的任务
List shutdownNow( );

任务调度线程池

在「任务调度线程池」功能加入之前,可以使用java.util.Timer来实现定时功能,Timer 的优点在于简单易
用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。

代码:

 public static void main(String[] args) {ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);pool.schedule(()->{System.out.println(Thread.currentThread()+"task1");int i=1/0;},1, TimeUnit.SECONDS);pool.schedule(()->{System.out.println(Thread.currentThread()+"task2");},1, TimeUnit.SECONDS);}

线程池中只有一个线程,所以线程只能串行运行,但是第一个线程代码出错,并不影响第二个线程的运行

定时执行

pool.scheduleAtFixedRate(): //上个线程开始到下个线程开始延时多长时间(如果线程执行时间大于延时时间,则按照线程执行结束后,立马开始下一个任务)
pool.scheduleWithFixedDelay()://从上一个线程结束延时指定时间后在执行下一个任务

处理线程池异常

1、任务自己用try块捉住

2、使用submit提交的返回值Future来判断(程序正常执行则返回正常结果,中间有异常则打印异常)

Future<Boolean> f = pool.submit(() -> {System.out.println("tsak");int i = 1 / 0;return true;
});
System.out.println(f.get());

定时执行任务

如何让每周四18:00 定时执行任务

(任务,当前时间和任务执行时间的时间差,间隔时间,时间单位)

public static void main(String[] args) throws Exception {//让每周周四18:00 定时执行任务LocalDateTime now=LocalDateTime.now();//线程安全的一个时间类//System.out.println(now);//获得周四时间LocalDateTime time = now.withHour(18).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.THURSDAY);//如果当前时间> 本周周四,必须找到下周周四if(now.compareTo(time)>0){time=time.plusWeeks(1);//加一周时间}//计算当前时间和要执行任务时间的差值long initailDelay = Duration.between(now, time).toMillis();long period=1000*60*60*24*7;//一周的时间间隔ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);pool.scheduleAtFixedRate(()->{System.out.println("running");},initailDelay,period,TimeUnit.MICROSECONDS);}time=time.plusWeeks(1);//加一周时间}//计算当前时间和要执行任务时间的差值long initailDelay = Duration.between(now, time).toMillis();long period=1000*60*60*24*7;//一周的时间间隔ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);pool.scheduleAtFixedRate(()->{System.out.println("running");},initailDelay,period,TimeUnit.MICROSECONDS);}

ThreadPoolExecutor和Executors相关推荐

  1. Android开发之线程池管理ThreadPoolExecutor和Executors.newSingleThreadExecutor()

    在Android开发中网络请求数据在Android4.0以后禁止在主线程请求,那么我们只有新开启线程请求数据了 一般都喜欢简单点这样写: new Thread(new Runnable() {@Ove ...

  2. 为什么阿里巴巴要禁用 Executors 创建线程池?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 转自:掘金,作者:何甜甜在吗 juejin.im/post/5dc ...

  3. 为什么阿里巴巴要禁用Executors创建线程池?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:何甜甜在吗 juejin.im/post/5dc41c165 ...

  4. 阿里内部禁用Executors创建线程池,为什么?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 何甜甜在吗 来源 | http://rrd.m ...

  5. 阿里巴巴为什么要禁用 Executors 创建线程池?

    作者:何甜甜在吗 www.juejin.im/post/5dc41c165188257bad4d9e69 看阿里巴巴开发手册并发编程这块有一条:线程池不允许使用 Executors 去创建,而是通过T ...

  6. 如何在队列排队之前让ThreadPoolExecutor将线程增加到最大数量

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,Bloc ...

  7. 线程池java.util.concurrent.ThreadPoolExecutor总结

    http://uule.iteye.com/blog/1123185 线程池还具有提高系统性能的优点,因为创建线程和清除线程的开销比较大. 有两种不同类型的线程池:一是固定线程数量的线程池:二是可变数 ...

  8. ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别

    前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍ThreadPoolExecutor接受任务相关的两方面入参的意义和区别,池大小参数corePoolS ...

  9. 线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?

    为什么要用线程池 基本的三个线程池的底层就是ThreadPoolExecutor类 ExecutorService threadPool = Executors.newFixedThreadPool( ...

最新文章

  1. 百度CTO王海峰服贸会展示AI新基建成果,飞桨获“科技创新服务示范案例”奖
  2. 体质测试java代码_求java代码,要求做一个测试类,实现以下功能之一。最好三个功能都有。...
  3. 怎么看rabbitmq的浏览器信息_买房沙盘怎么看?沙盘也可以看出很多信息的
  4. TimePicker的使用
  5. 深入剖析kafka架构内部原理
  6. php 图片印章_php工具型代码之印章抠图
  7. 2012 金华现场赛 A题
  8. Kent Beck 的《测试驱动开发》(TDD) Money示例Ruby版
  9. C#:将图片文件上传到数据库两种方法。
  10. sharepoint 使用命令行注册dll文件到gac的方法
  11. Luogu3178 [HAOI2015]树上操作
  12. 每年都要调两次时间,美国人已经烦透了
  13. 360极速浏览器安装chrome插件教程
  14. docker-nividia run 报错
  15. dll 不是 PML.NET callable问题解决办法
  16. ERIC6 打开项目报错
  17. Spring Boot 打包一站式解决方案
  18. 计算机点了注销有办法恢复吗,微信注销了还能恢复吗 账号注销了还能恢复吗...
  19. 微信小程序阶段总结一
  20. 外贸管理软件CRM、ERP对外贸企业有什么用?

热门文章

  1. 《Web GIS原理与应用开发》读书笔记(1)
  2. Instagram 5位传奇工程师背后的极简技术(PPT全译)
  3. 使用ArchiSteamFarm在树莓派挂卡
  4. HBase部署完成,Web UI界面无法打开有效解决方法
  5. 解决 Github 加载 ipynb 文件缓慢/失败
  6. 亚马逊退出中国市场 还要在欧洲站做无货源模式?
  7. 鬼画符门之点点大阵(python)
  8. QT + 百度智能云之人脸对比
  9. OTB数据集perfplot运行报错:索引超出矩阵维度
  10. oracle中映射表到timesten的方法