
JAVA线程和线程池
为什么要使用多线程?
从计算机来讲,线程是程序执行的最小单位,线程之间的切换和调用的成本低于进程。
从项目上来讲,多线程并发可以提高系统整体的并发能力与性能,可以支持更多的用户。
比如使用Windows右键删除有N个小文件的文件夹时,删除很缓慢,因为Windows使用的是单线程删除。而使用FastCopy进行多线程删除效率非常高,肉眼可见。
Java并发编程就是使用多线程来实现的,当使用多线程就会发现各种问题,其中就有线程管理问题,所以在JDK1.5版本引进的JUC包中提供了Executor这个调度器来创建线程池,对多线程进行管理。
Java创建线程的三种方式
使用Callable和Future(推荐)
实现Callable接口,重写call方法,实现接口的时候可以定义泛型,这个泛型是我们的call方法的返回值,也就是线程返回值。
call方法可以通过返回值获取业务的执行结果,并使用了线程池来管理线程。
继承Thread类
继承Thread类,重写run方法然后实例化,使用.start启动线程。
无法对线程进行有效的控制,没有返回值、异常,控制不了线程的创建数量,无限制的创建新线程可能会导致OOM。
实现Runnable接口
实现implements 接口,实现run方法,实例化传参给Thread,使用.start启动线程。
缺点和继承Thread的方式一样。
JUC中的线程池管理
在Java.util.concurrent中,提供了工具类Executors(调度器)对象来创建线程池,可以创建的线程池有四种:
可缓存线程池
没有最大线程数限制,池中如果没有空闲线程,会创建新线程加入到池中,如果有空闲线程会复用。
定长线程池
创建一个固定大小的线程池,池中有空闲线程就复用,没有则任务陷入等待,任务的默认调度算法是FIFO(先进先出)
单线程池
创建一个单线程化的线程池,它只会用唯一的线程来执行任务,保证所有任务按照指定顺序(基于FIFO, 先进先出原则)执行。
适用于需要保证任务串行执行的场景,比如某些数据处理流程要求严格按序执行的情况。
调度线程池
创建一个支持定时及周期性任务执行的线程池,主要用于需要延迟执行或者定期重复执行的任务,例如定时检查更新、周期性清理等任务。
可以理解为定时任务调度,实际我们并不使用这种方式进行定时任务调度,有其他更好的方式。
SpringBoot线程池
SpringBoot 对JAVA中的 ThreadPoolExecutor 进行了封装。
相关注解
@EnableAsync 类上添加,启动类或配置类,开启异步支持
@Async(value = "Bean 名称") 方法上添加,将这个方法执行异步操作
可以创建多个线程池,创建多个的原因是方便不同的业务使用。
如果所有业务共用一个线程池,可能会出现一个业务占满了所有线程,导致其他业务全部在队列等待中,无法访问的情况。
创建线程池
在一个配置类中,可以创建多个线程池,方法名为@Async(value = "Bean 名称") 中的Bean名称。
使用线程池
在方法上添加@Async(value = "Bean 名称") ,为需要异步的方法选择线程池
获取多线程的返回值
先要通过实现Future来创建一个返回类
在方法中使用返回类