线程池详解
线程池的种类:
1. JDK线程池----是java自带的API,比较偏底层,很少用,有必要了解
------(1)jdk普通线程池:ExecutorService
------(2)jdk定时任务线程池:ScheduledExecutorService
2. Spring线程池----做了封装
------(1)Spring普通线程池:ThreadPoolTaskExecutor
------(2)Spring定时任务线程池:ThreadPoolTaskScheduler
------(3)Spring普通线程池(简化版)
------(4)Spring定时任务线程池(简化版)
3.分布式定时任务线程池----Spring QuartZ
下面逐个用实列演示:
1.jdk普通线程池:ExecutorService------在Test中测试,代码如下:
1 @SpringBootTest 2 public class ThreadPoolTests { 3 4 private static final Logger logger =LoggerFactory.getLogger(ThreadPoolTests.class); 5 8 private ExecutorService executorService = Executors.newFixedThreadPool(5);//通过Executors这个工厂或者工具类创建线程,线程数量位5,哪个线程空闲就会执行任务 9 10 //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 11 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 12 try { 13 Thread.sleep(m); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 19 // 1.JDK普通线程池 20 @Test 21 public void testExecutorService() { 22 Runnable task = new Runnable() {//实现Runnable接口,这里是匿名实现,方法中写要执行的方法 23 @Override 24 public void run() { 26 logger.warn("Hello ExecutorService"); 27 } 28 }; 29 30 for (int i = 0; i < 10; i++) { 31 executorService.submit(task);//提交任务给线程池,就会安排线程处理 32 }
sleep(10000);//加上这个之后,打印结果之后程序还会运行秒,这是为了防止有的线程还没有打印完线程就结束了
33 35 }
插入:理解Thread.Sleep(10000)的含义,可以参考这篇文章https://blog.csdn.net/agony_sun/article/details/78031520
解释:Unix系统使用的是时间片算法,而Windows则属于抢占式的。抢占式表示,等一个进程用完CPU后,谁的优先级高,就给谁,而不是排队。一般情况下,一个进程除非自己主动放弃CPU 的试用权,不然不可以被剥夺。Thread.Sleep(10000)表示未来10000毫秒内(10秒内)该线程都不需要CPU资源,也就是说,这期间的CPU竞争都不会把该进程算在内(CPU竞争就是将这些线程的优先级排个序,看把CPU给谁用)。等到10钟到了的时候,该进程又会参与竞争。那么在这里,sleep(10000)的作用就是让testExecutorService()方法一直运行着,等到第10秒的时候,操作系统又会来这个方法中看,话有哪些进程参与竞争。但是
行结果如下:打印任务几乎同时完成,但是随机由不同的线程完成
2.JDK定时任务线程池
@SpringBootTest public class ThreadPoolTests { private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class); // JDK可执行定时任务的线程池 private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 try { Thread.sleep(m); } catch (InterruptedException e) { e.printStackTrace(); } } // 2.JDK定时任务线程池 @Test public void testScheduledExecutorService() { Runnable task = new Runnable() { @Override public void run() { logger.warn("Hello ScheduledExecutorService"); } }; //initialDelay:5000是点击执行之后到程序正式执行的延迟时间;period:1000是时间间隔;TimeUnit:时间单位
scheduledExecutorService.scheduleAtFixedRate(task, 5000,1000, TimeUnit.MILLISECONDS);
sleep(20000); //方法一开始运行就会生效,该方法总共会运行20秒;这里只是测试,需要这样让该方法一直运行,真实运行的项目不需要这样设置
}
执行结果如下图:不同的线程,每秒完成一次打印任务----总共执行了20秒,与设定的时间刚好—致,initialDelay了5秒,打印了15秒
3.Spring普通线程池
实现步骤:
步骤1:在application.properties配置线程数量等信息
1 # TaskExecutionProperties----Spring普通线程池 2 spring.task.execution.pool.core-size=5 3 spring.task.execution.pool.max-size=15 4 spring.task.execution.pool.queue-capacity=100
步骤2:写ThreadPoolConfig配置类
@Configuration @EnableScheduling//声明启用Scheduling,不然不会启用,会报错 @EnableAsync public class ThreadPoolConfig { }
步骤3:写测试代码
1 @SpringBootTest 2 public class ThreadPoolTests { 3 4 private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class); 5 6 // JDK可执行定时任务的线程池 7 private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); 8 9 //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 10 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 11 try { 12 Thread.sleep(m); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 } 17 // 3.Spring普通线程池 18 @Test 19 public void testThreadPoolTaskExecutor() { 20 Runnable task = new Runnable() { 21 @Override 22 public void run() { 23 24 logger.warn("Hello ThreadPoolTaskExecutor"); 25 } 26 }; 27 28 for (int i = 0; i < 10; i++) { 29 taskExecutor.submit(task); 30 } 31 32 sleep(10000);//加上这个之后,打印结果之后程序还会运行10秒,这是为了防止有的线程还没有打印完线程就结束了
33 }
运行结果:打印任务几乎同时完成,但是随机由不同的线程完成
4.Spring定时任务线程池
实现步骤:
步骤1:在application.properties配置线程数量等信息
1 # TaskSchedulingProperties-----Spring可执行定时任务的线程池 2 spring.task.scheduling.pool.size=5
步骤2:写ThreadPoolConfig配置类
1 @Configuration 2 @EnableScheduling//声明启用Scheduling,不然不会启用,会报错 3 @EnableAsync 4 public class ThreadPoolConfig { 5 }
步骤3:写测试代码
@SpringBootTest public class ThreadPoolTests { private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class); // JDK可执行定时任务的线程池 private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 try { Thread.sleep(m); } catch (InterruptedException e) { e.printStackTrace(); } } // 4.Spring定时任务线程池 @Test public void testThreadPoolTaskScheduler() { Runnable task = new Runnable() { @Override public void run() { logger.debug("Hello ThreadPoolTaskScheduler"); } }; Date startTime = new Date(System.currentTimeMillis() + 2000); taskScheduler.scheduleAtFixedRate(task, startTime, 1000); sleep(25000); }
执行结果如下图:不同的线程,每秒完成一次打印任务---总共执行了23秒,与设定的时间刚好—致,sleep()了25秒,System.currentTimeMillis() + 2000推迟了2秒
5.Spring普通线程池(简化)---配置比较多,但是任务较多时,比可以通过配置简化操作
步骤1:在AlphaService中写execute1,execute2方法,并加上注解 @Async
@Service public class AlphaService { private static final Logger logger = LoggerFactory.getLogger(AlphaService.class); @Async public void execute1() { logger.warn("execute1"); } }
步骤2:在application.properties配置线程数量等信息
1 # TaskExecutionProperties----Spring普通线程池 2 spring.task.execution.pool.core-size=5 3 spring.task.execution.pool.max-size=15 4 spring.task.execution.pool.queue-capacity=100
步骤3:写ThreadPoolConfig配置类
1 @Configuration 2 @EnableScheduling//声明启用Scheduling,不然不会启用,会报错 3 @EnableAsync 4 public class ThreadPoolConfig { 5 }
步骤4:写测试代码
1 @SpringBootTest 2 public class ThreadPoolTests { 3 4 private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class); 5 6 //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 7 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 8 try { 9 Thread.sleep(m); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 } 14 15 // 5.Spring普通线程池(简化) 16 @Test 17 public void testThreadPoolTaskExecutorSimple() { 18 for (int i = 0; i < 10; i++) { 19 alphaService.execute1(); 20 } 21 22 sleep(10000); 23 } 24 }
运行结果:
6.Spring可执行定时任务的线程池(简化)
步骤1:在AlphaService中写execute2方法,并加上注解@Scheduled
1 @Service 2 public class AlphaService { 3 4 private static final Logger logger = LoggerFactory.getLogger(AlphaService.class); 5 6 @Scheduled(initialDelay = 5000, fixedRate = 1000) 7 public void execute2() { 8 logger.warn("execute2"); 9 } 10 }
步骤2:在application.properties配置线程数量等信息
1 # TaskSchedulingProperties-----Spring可执行定时任务的线程池 2 spring.task.scheduling.pool.size=5
步骤3:写ThreadPoolConfig配置类
@Configuration @EnableScheduling//声明启用Scheduling,不然不会启用,会报错 @EnableAsync public class ThreadPoolConfig { }
步骤4:写测试代码
@SpringBootTest public class ThreadPoolTests { private static final Logger logger = LoggerFactory.getLogger(ThreadPoolTests.class); //Test中的线程执行完了就会结束,不会等一下看还有没有任务,因此需要定义一个sleep方法让这些线程等一下 private void sleep(long m) {//sleep方法经常抛异常,封装一下,处理一下异常 try { Thread.sleep(m); } catch (InterruptedException e) { e.printStackTrace(); } } // 6.Spring定时任务线程池(简化) @Test public void testThreadPoolTaskSchedulerSimple() { sleep(15000); } }
QuartZ请看https://i.cnblogs.com/posts/edit-done;postId=15914357