這篇文章給大家介紹如何進行ScheduledThreadPoolExecutor分析與線程池防坑,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
專注于為中小企業(yè)提供網站設計、成都做網站服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)林州免費做網站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯網行業(yè)人才,有力地推動了上1000+企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網站建設實現規(guī)模擴充和轉變。
線程池默認使用無界隊列,任務過多時,JVM OOM
不設置最大線程數,線程數目暴漲
定時執(zhí)行,執(zhí)行一次任務耗時太長甚至一直阻塞,達不到定時執(zhí)行的目的
線程池內的線程是非守護線程,停止JVM時出問題
使用submit方法,沒有調用future.get()導致異常被吞,execute不會有異常被吞的問題
死鎖問題,并不常見,但是有時候寫復雜了可能會出現。一句話,使用線程池和諸如阻塞隊列這種抽象層次比較高的工具時,盡量不要再用低層次的類,如lock,wait(),notify()等,這樣混用會導致難以排查的問題。
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(4); scheduledService.scheduleAtFixedRate(() -> { try { System.out.println("pool thread:" + Thread.currentThread().isDaemon()); System.out.println("start at:" + new Date()); Thread.sleep(10000); System.out.println("end at:" + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } }, 0, 5, TimeUnit.SECONDS);
上面的代碼塊意圖每5秒執(zhí)行一次任務,但是執(zhí)行這個任務需要耗費10秒(sleep),那么肯定不能達到5秒一次的效果。分析一下原因。
定時執(zhí)行功能的實現類是ScheduledThreadPoolExecutor
,它是一個線程池加延遲隊列來實現的,延遲隊列是使用堆來實現的,也就是根元素值最大或者值最小,在定時任務執(zhí)行這個場景下,根元素就是下一個要執(zhí)行的任務,然后有一個等待時間。
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); if (period <= 0) throw new IllegalArgumentException(); ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, triggerTime(initialDelay, unit), unit.toNanos(period)); RunnableScheduledFuture<Void> t = decorateTask(command, sft); sft.outerTask = t; delayedExecute(t); return t; }
然后看ScheduledFutureTask
這個類的run()
方法
public void run() { boolean periodic = isPeriodic();//是否周期執(zhí)行 if (!canRunInCurrentRunState(periodic)) cancel(false); else if (!periodic) ScheduledFutureTask.super.run();//不是執(zhí)行一次就完了 else if (ScheduledFutureTask.super.runAndReset()) {//執(zhí)行 setNextRunTime();//設置下次時間 reExecutePeriodic(outerTask);//加入隊列 } }
void reExecutePeriodic(RunnableScheduledFuture<?> task) { if (canRunInCurrentRunState(true)) { super.getQueue().add(task); if (!canRunInCurrentRunState(true) && remove(task)) task.cancel(false); else ensurePrestart();//決定線程池是否新增線程,未達到核心線程數,有新任務則加線程 } }
可以看到如果一次執(zhí)行時間很長,是達不到定時執(zhí)行的目的,最終的表現就是一次連著一次執(zhí)行,如果我們確實需要精準的定期執(zhí)行,不關注每次多長時間,該怎么辦?很簡單,再弄一個線程池專門用來干活
關于如何進行ScheduledThreadPoolExecutor分析與線程池防坑就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
文章標題:如何進行ScheduledThreadPoolExecutor分析與線程池防坑
鏈接分享:http://jinyejixie.com/article22/jjjccc.html
成都網站建設公司_創(chuàng)新互聯,為您提供App開發(fā)、靜態(tài)網站、企業(yè)網站制作、網站排名、網站維護、網站設計
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯