签名:但行好事,莫问前程。
前言
记录一多线程的三种创建方式以及创建自定义线程池的方式。
一、多线程的几种创建方式
1、继承Thread类
看源码可以发现Thread类也是实现了Runnable接口,由于Java是单继承的,所以这种方法一般使用的比较少。
2、实现Runnable接口
实现Runnable接口,将Runnable对象作为参数传入Thread作为参数,也可以开启线程,无返回值。
3、实现Callable接口
实现Callable接口,配合FutureTask使用,可以获取线程的返回结果。
4、线程池(重点,项目中使用比较多)
因为以上三种方式需要频繁创建销毁线程,所以我们在项目中使用的比较多的就是线程池。
自JDK1.5开始,Java提供了创建线程池的方式:
我们可以看到有很多实现线程池的方法:
我们看几种常用的线程池的创建方式:
- Executors.newFixedThreadPool() —不推荐
写个demo看一下:
public class MyThreadPoolDemo01 {
public static void main(String[] args) {
// 创建一个固定长度的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交任务
executorService.submit(new MyRun());
executorService.submit(new MyRun());
executorService.submit(new MyRun());
executorService.submit(new MyRun());
executorService.submit(new MyRun());
}
}
小结:我们可以看到,ExecutorService executorService = Executors.newFixedThreadPool(3); 我们给线程池设定了一个固定的长度后,尽管提交了5个线程,但是线程池只会创建3个线程去之执行这五个线程。
阿里云开发手册不推荐使用这个方式去创建线程池。原因:这个方式只指定了核心线程数,不能指定实现保活时间,不能选择阻塞队列、拒绝策略、线程名称等,所以阿里开发手册推荐我们创建线程池要使用自定义创建的方式。
- new ThreadPoolExecutor(此处省略七个线程池的参数) —重要,自定义创建线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
二、线程池的7个参数
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程最大存活时间
- unit:空闲线程最大存活时间的单位
- workQueue:任务队列
- threadFactory:线程工厂
- handler:任务的拒绝策略
其中前四个参数,见名知意,这里就过多研究。我们来看一下什么是任务队列、线程工厂、任务的拒绝策略:
BlockingQueue workQueue :任务队列,当核心线程数满了,没有达到最大线程数,这时候来了任务的时候,就会进入任务队列进行排队。
任务队列有一下几种实现方式:
ThreadFactory threadFactory:线程工厂,用的比较多的就是给我们自定义的线程指定一个线程名称,方便定位排查线程使用中遇到的问题。
线程工厂的实现类:
RejectedExecutionHandler handler:拒绝策略,当最大核心数和任务队列都满了,还有任务提交过来时的拒绝策略。
拒绝策略有以下几种:
自定义创建线程池:
public class MyThreadPoolDemo02 {
public static void main(String[] args) {
/**
* int corePoolSize,核心线程数
* int maximumPoolSize,最大线程数
* long keepAliveTime,空闲线程最大存活时间
* TimeUnit unit,空闲线程最大存活时间的单位
* BlockingQueue<Runnable> workQueue,任务队列
* ThreadFactory threadFactory,threadFactory
* RejectedExecutionHandler handler 任务的拒绝策略
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,
6,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("乐多多:");
return t;
}
},
new ThreadPoolExecutor.AbortPolicy()
);
threadPoolExecutor.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
});
}
}
运行结果:
三、线程池的执行流程
总结
博客主要记录了多线程的三种创建方式以及创建自定义线程池的方式,有啥错误或不足地方请指正,如果对你有所帮助,请一键三连。