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.总结
了解线程的使用场景
了解线程的创建方式
了解四种线程池
了解线程池实现原理