帶你快速搞定java并發(fā)庫
一、總覽
計算機(jī)程序 = 數(shù)據(jù) + 算法。
并發(fā)編程的一切根本原因是為了保證數(shù)據(jù)的正確性,線程的效率性。
Java并發(fā)庫共分為四個大的部分,如下圖
Executor 和 future 是為了保證線程的效率性
Lock 和數(shù)據(jù)結(jié)構(gòu) 是為了維持?jǐn)?shù)據(jù)的一致性。
Java并發(fā)編程的時候,思考順序為,
對自己的數(shù)據(jù)要么加鎖。要么使用提供的數(shù)據(jù)結(jié)構(gòu),保證數(shù)據(jù)的安全性
調(diào)度線程的時候使用Executor更好的調(diào)度。
二、Executor總覽
Executor 提供一種將任務(wù)提交與每個任務(wù)將如何運(yùn)行的機(jī)制(包括線程使用的細(xì)節(jié)、調(diào)度等)分離開來的方法。
相當(dāng)于manager,老板讓manager去執(zhí)行一件任務(wù),具體的是誰執(zhí)行,什么時候執(zhí)行,就不管了。
看上圖的繼承關(guān)系,介紹幾個
內(nèi)置的線程池基本上都在這里
newScheduledThreadPool
定時執(zhí)行的線程池
newCachedThreadPool
緩存使用過的線程
newFixedThreadPool
固定數(shù)量的線程池
newWorkStealingPool
將大任務(wù)分解為小任務(wù)的線程池
三、繼承結(jié)構(gòu)
構(gòu)造函數(shù)
包含一個定時的service
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); } static class DelegatedScheduledExecutorService extends DelegatedExecutorService implements ScheduledExecutorService { private final ScheduledExecutorService e; DelegatedScheduledExecutorService(ScheduledExecutorService executor) { super(executor); e = executor; }
四、怎么保證只有一個線程
定時執(zhí)行的時候調(diào)用這個方法,調(diào)用過程如下,注意看其中的注釋,由上往下的調(diào)用順序
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); if (delay <= 0) throw new IllegalArgumentException(); ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, triggerTime(initialDelay, unit), unit.toNanos(-delay)); RunnableScheduledFuture<Void> t = decorateTask(command, sft); sft.outerTask = t; // 延遲執(zhí)行 delayedExecute(t); return t; } private void delayedExecute(RunnableScheduledFuture<?> task) { if (isShutdown()) reject(task); else { // 加入任務(wù)隊列 super.getQueue().add(task); if (isShutdown() && !canRunInCurrentRunState(task.isPeriodic()) && remove(task)) task.cancel(false); else // 確保執(zhí)行 ensurePrestart(); } } // 如果worker數(shù)量小于corePoolSize,創(chuàng)建新的線程,其他情況不處理 void ensurePrestart() { int wc = workerCountOf(ctl.get()); if (wc < corePoolSize) addWorker(null, true); else if (wc == 0) addWorker(null, false); }
五、怎么保證時間可以定時執(zhí)行
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); RunnableScheduledFuture<?> t = decorateTask(command, new ScheduledFutureTask<Void>(command, null, triggerTime(delay, unit))); delayedExecute(t); return t; }
在每次執(zhí)行的時候會把下一次執(zhí)行的時間放進(jìn)任務(wù)中
private long triggerTime(long delay, TimeUnit unit) { return triggerTime(unit.toNanos((delay < 0) ? 0 : delay)); } /** * Returns the trigger time of a delayed action. */ long triggerTime(long delay) { return now() + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); }
FutureTask 定時是通過LockSupport.parkNanos(this, nanos);LockSupport.park(this);
private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; } else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } //注意這里 LockSupport.parkNanos(this, nanos); } else //注意這里 LockSupport.park(this); } }
總結(jié):Executor是通過將任務(wù)放在隊列中,生成的futureTask。然后將生成的任務(wù)在隊列中排序,將時間最近的需要出發(fā)的任務(wù)做檢查。如果時間不到,就阻塞線程到下次出發(fā)時間。
注意:newSingleThreadScheduledExecutor只會有一個線程,不管你提交多少任務(wù),這些任務(wù)會順序執(zhí)行,如果發(fā)生異常會取消下面的任務(wù),線程池也不會關(guān)閉,注意捕捉異常
六、使用
ScheduledExecutorService single = Executors.newSingleThreadScheduledExecutor(); Runnable runnable1 = () -> { try { Thread.sleep(4000); System.out.println("11111111111111"); } catch (InterruptedException e) { e.printStackTrace(); } }; Runnable runnable2 = () -> { try { Thread.sleep(4000); System.out.println("222"); } catch (InterruptedException e) { e.printStackTrace(); } }; single.scheduleWithFixedDelay(runnable1,0,1, TimeUnit.SECONDS); single.scheduleWithFixedDelay(runnable2,0,2, TimeUnit.SECONDS);
11111111111111 222 11111111111111 222 11111111111111
在項目中要注意關(guān)閉線程池
actionService = Executors.newSingleThreadScheduledExecutor(); actionService.scheduleWithFixedDelay(() -> { try { Thread.currentThread().setName("robotActionService"); Integer robotId = robotQueue.poll(); if (robotId == null) { // 關(guān)閉線程池 actionService.shutdown(); } else { int aiLv = robots.get(robotId); if (actionQueueMap.containsKey(aiLv)) { ActionQueue actionQueue = actionQueueMap.get(aiLv); actionQueue.doAction(robotId); } } } catch (Exception e) { // 捕捉異常 LOG.error("",e); } }, 1, 1, TimeUnit.SECONDS);
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
一文詳解Java?etcd的應(yīng)用場景及編碼實戰(zhàn)
etcd?是一個高度一致的分布式鍵值存儲系統(tǒng)。本文旨在幫助大家理解etcd,從宏觀角度俯瞰etcd全局,掌握etcd的基本操作技能,需要的可以參考一下2022-08-08SpringMVC @ResponseBody 415錯誤處理方式
這篇文章主要介紹了SpringMVC @ResponseBody 415錯誤處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Java怎么獲取當(dāng)前時間、計算程序運(yùn)行時間源碼詳解(超詳細(xì)!)
有的時候,我們需要查看某一段代碼的性能如何,最為簡單的方式,可以通過計算該段代碼執(zhí)行的耗時,來進(jìn)行簡單的判斷,這篇文章主要給大家介紹了關(guān)于Java怎么獲取當(dāng)前時間、計算程序運(yùn)行時間的相關(guān)資料,需要的朋友可以參考下2024-07-07詳談cxf和axis兩種框架下的webservice客戶端開發(fā)
這篇文章主要介紹了詳談cxf和axis兩種框架下的webservice客戶端開發(fā),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08在SpringBoot中使用@Value注解來設(shè)置默認(rèn)值的方法
Spring Boot提供了一種使用注解設(shè)置默認(rèn)值的方式,即使用 @Value 注解,下面這篇文章主要給大家介紹了關(guān)于如何在SpringBoot中使用@Value注解來設(shè)置默認(rèn)值的相關(guān)資料,需要的朋友可以參考下2023-10-10springboot項目數(shù)據(jù)庫密碼如何加密
在我們?nèi)粘i_發(fā)中,我們可能很隨意把數(shù)據(jù)庫密碼直接明文暴露在配置文件中,今天就來聊聊在springboot項目中如何對數(shù)據(jù)庫密碼進(jìn)行加密,感興趣的可以了解一下2021-07-07SpringBoot定時任務(wù)動態(tài)擴(kuò)展ScheduledTaskRegistrar詳解
這篇文章主要為大家介紹了SpringBoot定時任務(wù)動態(tài)擴(kuò)展ScheduledTaskRegistrar類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01