【JAVA】_001_多线程之线程池


1.认识线程

什么是进程?

  • 正在运行的程序,是线程的集合

什么是线程?

  • 正在独立执行的一条执行路径,多线程是为了提高程序效率

1.1.线程的创建及生命周期

创建方式:

  • 继承Thread类

  • 实现Runable接口

    • 内部是run方法,无返回值,不可抛出异常
  • 实现callable接口

    • 内部是call方法,有返回值,可抛出异常
  • 使用匿名内部类

  • 线程池(企业使用)

生命周期:创建、就绪、运行、阻塞、死亡

sleep与wait的区分:
1.sleep是Thread的静态本地方法,wait是object类的静态本地方法
2.Sleep不释放锁
3.Sleep不依赖synchronized关键字
4.Sleep不用唤醒
5.Sleep用于当前线程休眠,wait用于多线程间通信
6.Sleep会让出CPU执行时间切强制上下文转换,wait后可能还有机会重新竞争到锁继续执行。

yield与jion:

  • yield()执行后线程直接进入就绪状态,马上释放CPU执行权,但保留CPU执行资格,有可能获得执行权继续执行
  • Join()执行后线程进入阻塞状态

守护线程(如gc线程):为每个用户线程提供服务的线程,当没有用户线程时,守护线程会自动消亡。

  • 特征:与主线程一起销毁

1.2.线程池

优势
- 降低资源消耗
- 提高响应速度
- 提高线程可管理性

线程池核心是走ThreadPoolExecutor构造函数

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

线程池类型:

  • Executors.newCachaedthreadPool():创建一个可缓存的线程池,如超过线程池长度,可灵活回收空闲线程,无空闲时则新建线程。
  • Executors.newFixedThreadPool(数量):创建一个定长线程池,可控制线程最大并发数,超出的会在队列中等待。
  • Executors.newScheduledThreadPool(数量):创建一个定长线程池,支持定时及周期性执行任务。
  • Executors.newSingleThreadExecutor():创建一个单线程化的线程池,只会用唯一工作线程执行任务,保证FIFO。
  • Executors.ewSingleThreadScheduledExecutor:创建支持定时及周期性任务执行的单核心线程池
  • Executors.newWorkStealingPool:创建一个具有抢占式操作的线程池。1.8新增的一个并行的线程池,参数中传入的是一个线程并发的数量,和之前就有很明显的区别,前面几种线程池都有核心线程数、最大线程数等等,而这里使用了一个并发线程数解决问题。

参数:

  • Corepoolesize:核心线程数,创建了就不会销毁,是一种常驻线程
  • Maxnumpoolsize:最大线程数
  • KeepAliveTime:设置超过核心线程之外的的线程存活时间
  • Unit超时秒数。
  • Workqueue:用来存放待执行的任务
  • ThreadFactory:线程工厂,用来生产线程
  • Handler:任务拒绝策略(第一种是当调用shutdown等方法关闭线程池后,想再让线程池再提交任务就会遭到拒绝,第二种就是最大线程数已满是,再有任何会执行任务拒绝策略)

线程池配置:

  • IO密集型:操作数据库,IO等待过多,大部分线程阻塞时,需要多配置线程数,2*cpu核数。
  • CPU密集型:cpu使用频率高,线程数与CPU数相同即可

线程池处理流程:

1、判断核心线程数是否已满,未满则创建核心线程,满了则放入任务队列。

2、判断任务队列是否已满,未满则放入队列,满了则创建临时线程。

3、判断最大线程数是否已满,未满则创建临时线程,满了则执行任务拒绝策略。

PS:优先添加队列而不是创建线程:创建线程需获取全局锁,影响效率

复用原理

​ 线程池对线程和任务进行了解耦,核心原理是线程池对Thread方法进行了封装,并不是每次执行任务都会调用start方法,而是让每个线程循环执行任务,不断检查是否有任务需要执行,有则直接调用run方法作为普通方法执行。

1.3.总结

  • 了解线程的使用场景

  • 了解线程的创建方式

  • 了解四种线程池

  • 了解线程池实现原理


文章作者: truly
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 truly !
  目录