<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前兩天做專案的時候,想提高一下插入表的效能優化,因為是兩張表,先插舊的表,緊接著插新的表,一萬多條資料就有點慢了
後面就想到了執行緒池ThreadPoolExecutor,而用的是Spring Boot專案,可以用Spring提供的對ThreadPoolExecutor封裝的執行緒池ThreadPoolTaskExecutor,直接使用註解啟用
先建立一個執行緒池的設定,讓Spring Boot載入,用來定義如何建立一個ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync這兩個註解,表示這是個設定類,並且是執行緒池的設定類
@Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Value("${async.executor.thread.core_pool_size}") private int corePoolSize; @Value("${async.executor.thread.max_pool_size}") private int maxPoolSize; @Value("${async.executor.thread.queue_capacity}") private int queueCapacity; @Value("${async.executor.thread.name.prefix}") private String namePrefix; @Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //設定核心執行緒數 executor.setCorePoolSize(corePoolSize); //設定最大執行緒數 executor.setMaxPoolSize(maxPoolSize); //設定佇列大小 executor.setQueueCapacity(queueCapacity); //設定執行緒池中的執行緒的名稱字首 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當pool已經達到max size的時候,如何處理新任務 // CALLER_RUNS:不在新執行緒中執行任務,而是有呼叫者所在的執行緒來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //執行初始化 executor.initialize(); return executor; } }
@Value是我設定在application.properties,可以參考設定,自由定義
# 非同步執行緒設定 # 設定核心執行緒數 async.executor.thread.core_pool_size = 5 # 設定最大執行緒數 async.executor.thread.max_pool_size = 5 # 設定佇列大小 async.executor.thread.queue_capacity = 99999 # 設定執行緒池中的執行緒的名稱字首 async.executor.thread.name.prefix = async-service-
建立一個Service介面,是非同步執行緒的介面
public interface AsyncService { /** * 執行非同步任務 * 可以根據需求,自己加引數擬定,我這裡就做個測試演示 */ void executeAsync(); }
實現類
@Service public class AsyncServiceImpl implements AsyncService { private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class); @Override @Async("asyncServiceExecutor") public void executeAsync() { logger.info("start executeAsync"); System.out.println("非同步執行緒要做的事情"); System.out.println("可以在這裡執行批次插入等耗時的事情"); logger.info("end executeAsync"); } }
在executeAsync()方法上增加註解@Async("asyncServiceExecutor"),asyncServiceExecutor方法是前面ExecutorConfig.java中的方法名,表明executeAsync方法進入的執行緒池是asyncServiceExecutor方法建立的
接下來就是在Controller裡或者是哪裡通過註解@Autowired注入這個Service
@Autowiredprivate AsyncService asyncService; @GetMapping("/async") public void async(){ asyncService.executeAsync(); }
紀錄檔列印
2022-07-16 22:15:47.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:15:47.655 INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:15:48.833 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:15:48.834 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:15:48.986 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:15:48.987 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
通過以上紀錄檔可以發現,[async-service-]是有多個執行緒的,顯然已經在我們設定的執行緒池中執行了,並且每次請求中,controller的起始和結束紀錄檔都是連續列印的,表明每次請求都快速響應了,而耗時的操作都留給執行緒池中的執行緒去非同步執行;
雖然我們已經用上了執行緒池,但是還不清楚執行緒池當時的情況,有多少執行緒在執行,多少在佇列中等待呢?這裡我建立了一個ThreadPoolTaskExecutor的子類,在每次提交執行緒的時候都會將當前執行緒池的執行狀況列印出來
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.concurrent.ListenableFuture; import java.util.concurrent.Callable;import java.util.concurrent.Future;import java.util.concurrent.ThreadPoolExecutor; /** * @Author: 騰騰 * @Date: 2022/7/16/0016 22:19 */ public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor { private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class); private void showThreadPoolInfo(String prefix) { ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor(); if (null == threadPoolExecutor) { return; } logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]", this.getThreadNamePrefix(), prefix, threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size()); } @Override public void execute(Runnable task) { showThreadPoolInfo("1. do execute"); super.execute(task); } @Override public void execute(Runnable task, long startTimeout) { showThreadPoolInfo("2. do execute"); super.execute(task, startTimeout); } @Override public Future<?> submit(Runnable task) { showThreadPoolInfo("1. do submit"); return super.submit(task); } @Override public <T> Future<T> submit(Callable<T> task) { showThreadPoolInfo("2. do submit"); return super.submit(task); } @Override public ListenableFuture<?> submitListenable(Runnable task) { showThreadPoolInfo("1. do submitListenable"); return super.submitListenable(task); } @Override public <T> ListenableFuture<T> submitListenable(Callable<T> task) { showThreadPoolInfo("2. do submitListenable"); return super.submitListenable(task); } }
如上所示,showThreadPoolInfo方法中將任務總數、已完成數、活躍執行緒數,佇列大小都列印出來了,然後Override了父類別的execute、submit等方法,在裡面呼叫showThreadPoolInfo方法,這樣每次有任務被提交到執行緒池的時候,都會將當前執行緒池的基本情況列印到紀錄檔中;
修改ExecutorConfig.java的asyncServiceExecutor方法,將ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()改為ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor()
@Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); //在這裡修改 ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); //設定核心執行緒數 executor.setCorePoolSize(corePoolSize); //設定最大執行緒數 executor.setMaxPoolSize(maxPoolSize); //設定佇列大小 executor.setQueueCapacity(queueCapacity); //設定執行緒池中的執行緒的名稱字首 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當pool已經達到max size的時候,如何處理新任務 // CALLER_RUNS:不在新執行緒中執行任務,而是有呼叫者所在的執行緒來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //執行初始化 executor.initialize(); return executor; }
再次啟動該工程測試
2022-07-16 22:23:30.951 INFO 14088 --- [nio-8087-exec-2] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [0], completedTaskCount [0], activeCount [0], queueSize [0]
2022-07-16 22:23:30.952 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:23:30.953 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:23:31.351 INFO 14088 --- [nio-8087-exec-3] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [1], completedTaskCount [1], activeCount [0], queueSize [0]
2022-07-16 22:23:31.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:23:31.353 INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:23:31.927 INFO 14088 --- [nio-8087-exec-5] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [2], completedTaskCount [2], activeCount [0], queueSize [0]
2022-07-16 22:23:31.929 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:23:31.930 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2022-07-16 22:23:32.496 INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]
2022-07-16 22:23:32.498 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
非同步執行緒要做的事情
可以在這裡執行批次插入等耗時的事情
2022-07-16 22:23:32.499 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
注意這一行紀錄檔:
2022-07-16 22:23:32.496 INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]
這說明提交任務到執行緒池的時候,呼叫的是submit(Callable task)這個方法,當前已經提交了3個任務,完成了3個,當前有0個執行緒在處理任務,還剩0個任務在佇列中等待,執行緒池的基本情況一路瞭然;
到此這篇關於Spring Boot使用執行緒池處理上萬條資料插入的文章就介紹到這了,更多相關Spring Boot執行緒池處理上萬條資料插入內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45