Spring Boot中Java主线程与线程池任务的执行顺序及控制问题
Spring Boot线程池任务执行相关问题解答
场景说明
我有一个Spring Boot演示项目,应用启动时会创建线程池。主线程中包含两个任务:
- Task A:包含大量API调用,会提交至线程池执行
- Task B:仅包含数据库查询操作,直接在主线程执行
以下是针对三个技术问题的解答:
问题1:采用示例代码实现时,Task B是否会比Task A更早执行?
大概率会。调用executor.submit()只是将Task A提交到线程池的任务队列,线程池需要调度空闲线程来启动这个任务,这个调度过程存在一定开销。而主线程提交完Task A后会立即执行Task B,不会等待线程池启动Task A,所以Task B几乎肯定会比Task A先开始执行,甚至可能在Task A还未启动时就已执行完成。
问题2:是否可以让Task B等待Task A执行完成后再执行?若可行,该如何实现?
可以,有几种简单的实现方式:
- 方式一:利用Future阻塞等待
submit()方法会返回Future对象,调用其get()方法会阻塞主线程,直到Task A执行完成:public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(5); // 提交Task A并获取Future Future<?> taskAFuture = executor.submit(() -> { // process 1: fetch API // process 2: call Database // process 3: fetch API // process 4: call Database }); // 主线程阻塞,等待Task A执行完成 taskAFuture.get(); // Task B开始执行 db.query(xxx); } - 方式二:使用CountDownLatch
初始化一个计数为1的CountDownLatch,Task A执行完毕后调用countDown(),主线程调用await()等待计数归零:public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(5); CountDownLatch latch = new CountDownLatch(1); executor.submit(() -> { try { // process 1: fetch API // process 2: call Database // process 3: fetch API // process 4: call Database } finally { // Task A执行完成,计数减1 latch.countDown(); } }); // 主线程阻塞等待 latch.await(); // Task B开始执行 db.query(xxx); } - 方式三:关闭线程池并等待终止(适合线程池不再复用的场景)
如果Task A是线程池的最后一个任务,可以先关闭线程池,再等待所有任务执行完成:public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(() -> { // process 1: fetch API // process 2: call Database // process 3: fetch API // process 4: call Database }); // 关闭线程池,不再接受新任务 executor.shutdown(); // 等待所有已提交任务执行完成 executor.awaitTermination(1, TimeUnit.HOURS); // Task B开始执行 db.query(xxx); }
问题3:假设线程池无空闲工作线程处理Task A,会出现什么情况?主线程是否会跳过Task A优先执行Task B?
当线程池没有空闲线程时,Task A会被放入线程池的任务队列(newFixedThreadPool默认使用无界的LinkedBlockingQueue)等待,这个提交过程不会阻塞主线程。主线程提交完Task A后会立即执行Task B,不会因为Task A未被执行而等待,所以Task B依然会优先执行,和线程池是否有空闲线程无关。
内容的提问来源于stack exchange,提问作者auntR
相关产品推荐
相关产品推荐

