线程
- 何为线程?
进程是分配资源的最小单位,线程是任务执行的最小单位。 - 为什么要引入多线程?
在以前的时代,cpu都是单核的,这样只要有一和io请求进来,cpu就会阻塞先去执行io请求,当时的多线程是为了解决CPU的利用率的问题,多线程在当时可以在io请求来的时候开一个线程去执行io请求,这样就可以提高CPU的利用率
在现在的多核时代,多线程技术可以提高电脑任务的吞吐率,可以允许多个任务并发执行,一个线程需要使用一个核心 - 多线程避免不了上下文切换,什么是上下文切换?
我们的CPU核心数量是有限的,而任务是可能开启很多个的,所以每个线程都有自己的CPU时间片,又或者线程之间进行通信的时候,涉及到互斥资源和需要处理同步问题的时候也需要线程的上下文切换
一个线程到另外一个线程的时候,本地变量表、程序计数器等状态信息需要保存,然后切换到另外一个线程继续执行,一次线程的状态保存和加载的过程就是上下文切换 - 线程的通信方式?
- 互斥量
- 信号量(Semaphore)
- 事件(noitfy、wait等)
- 多线程的坏处?
- 需要处理好同步与互斥的关系
- 设计上下文切换,耗时长
- 可能会造成死锁问题
线程池
为什么要使用线程池
- 降低资源消耗
- 提高响应速度
- 提高线程的可管理性
Java创建线程的方式
- 使用Executors工具类进行创建,不推荐,因为这种方式在newFixedThreadPool和newCallerRunsThreadPool的方法中允许线程的最大数量为Integer.MAX_VALUE还有newCacheThreadPool和newScheduleThreadPool中允许线程添加的数量为Integer.MAX_VALUE
- 使用ThreadPoolExecutor自己new一个出来并且进行参数设置,Java阿里巴巴的开发手册也是推荐使用这种方式。
ThreadPoolExecutor创建线程池的参数解析
corePoolSize:线程池中线程的核心数量,也是线程池中一开始创建就有的线程的最小数量
maxinumPoolSize:最多允许同时允许的线程数量
keepAliveTime:当提交的任务超过核心线程数量的时候,新创建的线程数执行完任务后可以存活的时间
TimeUnti:keepAliveTime的时间单位
ThreadFactory:创建线程的时候会使用到
BlockingQueue:任务队列
RejectExecutionHandler:拒绝策略
几种Java线程池的拒绝策略
- ThreadPoolExecutor.AbortPolicy:拒绝新任务(Spring线程池默认的拒绝策略)
- ThreadPoolExecutor.CallerRunsPolicy:如果线程池中没有空闲的线程,就将任务加入任务队列
- ThreadPoolExecutor.DiscardPolicy:抛弃新任务
- ThreadPoolExecutor.DiscardOldestPolicy:抛弃加入等待任务队列中时间最久的任务