Java线程池ExecutorService和Executors应用(Spring Boot微服务)
记录:476
场景:在Spring Boot微服务中使用ExecutorService管理Java线程池。使用Executors创建线程池。使用Runnable接口实现类提交线程任务到线程池执行。
版本:JDK 1.8,Spring Boot 2.6.3。
1.线程和线程池基础
JDK自带线程和线程池包位置:java.util.concurrent.*,以及java.lang.Runnable和java.lang.Thread在java.lang.*中。
1.1线程接口Runnable
接口全称:java.lang.Runnable。
接口注释:The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread.
说明:提交给线程执行的类需实现Runnable接口。该接口只有一个抽象方法public abstract void run()。具体业务逻辑如需被线程调用的话,必须在此run方法内调用业务逻辑。
1.2线程Thread
类全称:java.lang.Thread。
类注释:A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
说明:线程java.lang.Thread实现了java.lang.Runnable接口。在java.lang.Thread中维护了JVM中对线程的属性和方法的操作。方法包括线程创建、初始化、启动、运行、停止等。属性包括
线程名称、优先级、守护进程标志位、线程组、线程本地变量等。
接收Runnable线程任务方式:一般在创建Thread线程对象时,在有参构造函数的输入参数中传入自定义线程任务(实现Runnable接口的对象)。比如:public Thread(Runnable target)。
1.3线程池
(1)接口
java.util.concurrent.Executor,线程池顶层接口,只有一个抽象方法void execute(Runnable command)。此方法执行提交给线程池已实现Runnable接口的线程任务。
java.util.concurrent.ExecutorService,线程池接口,实现java.util.concurrent.Executor接口。此接口中主要提供线程池提交任务的submit方法、和invokeAll方法等方法。
(2)抽象类
java.util.concurrent.AbstractExecutorService,线程池默认实现方式,在AbstractExecutorService中提供默认的实现ExecutorService接口的方式。
(3)实现类
java.util.concurrent.ThreadPoolExecutor,线程池实现类。
主要是对线程池的创建、运行、维护等方面管理。
属性包括运行状态、线程池大小、线程池任务数量、线程池工厂类ThreadFactory、线程池工作线程、线程池同步线程锁、线程池任务队列BlockingQueue<Runnable> workQueue等。
方法包括一序列有参构造函数创建线程池、线程池执行任务方法void execute(Runnable command),以及获取线程池相关属性的get方法和设置线程池相关属性的set方法。
1.4线程池创建工具类Executors
全称:java.util.concurrent.Executors。
说明:在Executors中包括一序列创建线程池的静态方法,此类构造方法是private类型,因此不可被实例化。
类方法包括如下,可按需选择。
public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
public static ExecutorService newWorkStealingPool();
public static ExecutorService newWorkStealingPool(int parallelism)
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) ;
public static ExecutorService newCachedThreadPool();
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
public static ScheduledExecutorService newSingleThreadScheduledExecutor();
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);
1.5其它
(1)线程专用的一些类
java.lang.Runnable
java.util.concurrent.Callable
java.util.concurrent.Future
java.util.concurrent.FutureTask
(2)线程工程类
线程池工厂(接口)
java.util.concurrent.ThreadFactory
线程池工厂(实现类)
java.util.concurrent.Executors.DefaultThreadFactory
java.util.concurrent.Executors.PrivilegedThreadFactory
(3)调度类线程体现
接口
java.util.concurrent.Executor
java.util.concurrent.ExecutorService
java.util.concurrent.ScheduledExecutorService
实现类
java.util.concurrent.ThreadPoolExecutor
实现类
java.util.concurrent.ScheduledThreadPoolExecutor
(4)其它
java.lang.SecurityManager
java.util.concurrent.ThreadPoolExecutor.Worker
2.使用Spring Boot注解配置线程池ExecutorService
(1)说明
ThreadPoolExecutor,全称:java.util.concurrent.ExecutorService。
使用@Bean("executorServiceHz")注解把线程池注入到Spring IOC容器中。
(2)代码
@Configuration
public class ThreadPoolConfig {
/**
* 创建线程池
*/
@Bean("executorServiceHz")
public ExecutorService executorService() {
ExecutorService executorService = Executors.newFixedThreadPool(8, new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable);
}
});
return executorService;
}
}
3.实现Runnable接口的线程任务类
(1)说明
提交给线程池任务,需实现Runnable接口。
Runnable接口的run方法里面就是线程具体执行的业务逻辑。
(2)代码
public class SportContestExecutor implements Runnable {
private TaskDto taskDto;
public SportContestExecutor(TaskDto taskDto) {
this.taskDto = taskDto;
}
@Override
public void run() {
String eventName = this.taskDto.getEventName();
String content = this.taskDto.getContent();
System.out.println("【线程: " + Thread.currentThread().getName() + ",在直播: " + eventName + content + "】");
}
}
4.把实现Runnable接口的线程任务类提交到线程池
(1)说明
Runnable接口的线程任务类需提交到线程池才能具体执行。
(2)代码
@Component("sportWorker02")
public class SportWorker02 {
/**
* 自动注入线程池
*/
@Autowired
private ExecutorService executorServiceHz;
/**
* 把线程任务提交到线程池
*/
public void holdGame() {
//1.准备数据
List<TaskDto> groupStage = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String no = "" + (i + 1);
if (i < 9) {
no = "0" + (i + 1);
}
TaskDto taskDto01 = TaskDto.builder().eventName("羽毛球球比赛").content("小组赛" + no).build();
groupStage.add(taskDto01);
}
//2.线程任务提交到线程池
for (TaskDto taskDto : groupStage) {
executorServiceHz.execute(new SportContestExecutor(taskDto));
}
}
}
5.测试示例
(1)说明
直接在SpringBoot的启动类的main函数中测试。
在执行完成SpringApplication.run(Example212Application.class)后,SpringBoot的环境已经创建完成。
(2)代码
@SpringBootApplication
public class Example212Application {
public static void main(String[] args) {
SpringApplication.run(Example212Application.class);
SportWorker02 sportWorker02 = SpringUtil.getBean("sportWorker02");
sportWorker02.holdGame();
}
}
(3)输出结果
【线程: Thread-5,在直播: 羽毛球球比赛小组赛02】
【线程: Thread-4,在直播: 羽毛球球比赛小组赛01】
【线程: Thread-6,在直播: 羽毛球球比赛小组赛03】
【线程: Thread-7,在直播: 羽毛球球比赛小组赛04】
【线程: Thread-8,在直播: 羽毛球球比赛小组赛05】
【线程: Thread-7,在直播: 羽毛球球比赛小组赛09】
【线程: Thread-5,在直播: 羽毛球球比赛小组赛10】
【线程: Thread-10,在直播: 羽毛球球比赛小组赛07】
【线程: Thread-9,在直播: 羽毛球球比赛小组赛06】
【线程: Thread-11,在直播: 羽毛球球比赛小组赛08】
6.辅助实体类
(1)说明
在实体类中使用注解@Data等来自lombok-1.18.24.jar。
(2)TaskDto
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TaskDto implements Serializable {
//赛事名称
private String eventName;
//活动内容
private String content;
}
以上,感谢。
2023年9月14日