摘要:一個線程池包含很多準備運行的空閑線程,每當執行完畢后,線程不會死亡而是回到線程池準備為下一個請求提供服務。另一個使用線程池的理由是減少并發線程數。創建大量線程會大大降低性能甚至拖垮虛擬機。
【Future的概念
interface Future
public interface Future{ //取消計算,如果尚未開始,直接取消不再運算,如果正在進行:mayInterruptIfRunning等于true就會被中斷。注意一點:只要調用了cancle(),無論任務是否能夠執行,再調用get()都會出現cancledException,這是由于Future.state的狀態被置為CANCELLED = 4,所致的; boolean cancel(boolean mayInterruptIfRunning) //判斷計算是否取消。 boolean isCancelled(); //判斷計算是否完成,如果計算完成返回true,否則返回false boolean isDone(); //獲得異步計算的結果,如果在調用get()的時候結果還沒有計算出來,調用線程將被阻塞。 V get() throws InterruptedException, ExecutionException; //獲得異步計算的結果,如果在調用get()的時候結果還沒有計算出來,調用線程將被阻塞。如果調用超時將會拋出TimeoutException。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
補充:
- FutureTask:包裝器,可以將Callable轉換成為Future與Runnable,它同時實現了二者的接口。 - Callable:可以為異步方法返回計算結果。【下面我們實現一種基于Future的場景
public class Exercise { private SimpleApplicationService simpleApplicationService = new SimpleApplicationService(); @Test public void futureTest() throws InterruptedException, ExecutionException { long st = System.currentTimeMillis(); //這里本是一callable接口實現,我用lambda方便一點 FutureTask result = new FutureTask【反思一些問題:(() -> simpleApplicationService.query()); //記住我們的任務都與需要開啟一個新的線程 Thread t = new Thread(result); t.start(); long end = System.currentTimeMillis(); System.out.println("耗時:" + (end - st) + " 結果:" + result.get()); } } public class SimpleApplicationService { public String query() throws InterruptedException { System.out.println("開始查詢"); Thread.sleep(2000); return "query result"; } }
每個異步方法都需要新開啟一個線程這樣很消耗資源。
每次都要new一個thread挺麻煩的。
【解決方案:使用線程池構建一個新的線程是有代價的,因為設計到與操作系統的交互。如果程序中創建了大量的并且生命周期很短的線程,我們應該使用線程池。
一個線程池包含很多準備運行的空閑線程,每當run()執行完畢后,線程不會死亡而是回到線程池準備為下一個請求提供服務。
另一個使用線程池的理由是減少并發線程數。創建大量線程會大大降低性能甚至拖垮虛擬機。
【Executor介紹Executors類有許多靜態方法可創建線程池。例如:
Executors.newCachedThreadPool():對于一個任務,有空閑線程可用則會立即執行,否則創建一個新的線程??臻e線程存活60s。
Executors.newFixedThreadPool(n):構建具有固定大小的線程池,若任務多余空閑線程數,則將多余任務放置等待隊列中。
Executors.newSingleThreadExecutor():只有一個空閑線程的線程池,任務執行一個接一個;
以上三個方法返回ExecutorService接口的ThreadPoolExecutor對象。
核心(簡介):
ThreadPoolExecutor
public class ThreadPoolExecutor extends AbstractExecutorService { public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueueworkQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,RejectedExecutionHandler handler); //事實上,前面三個構造器都是調用的第四個構造器進行的初始化工作。 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); }
參數含義:
corePoolSize:核心池的大小,這個參數跟后面講述的線程池的實現原理有非常大的關系。在創建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務到來才創建線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法。從這2個方法的名字就可以看出,是預創建線程的意思,即在沒有任務到來之前就創建corePoolSize個線程或者一個線程。默認情況下,在創建了線程池后,線程池中的線程數為0。當有任務來之后,就會創建一個線程去執行任務,當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中;
maximumPoolSize:線程池最大線程數,這個參數也是一個非常重要的參數,它表示在線程池中最多能創建多少個線程;
keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。默認情況下,只有當線程池中的線程數大于corePoolSize時,keepAliveTime才會起作用。直到線程池中的線程數不大于corePoolSize,即當線程池中的線程數大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大于corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0;
unit:參數keepAliveTime的時間單位
workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這里的阻塞隊列有以下幾種選擇:
- ArrayBlockingQueue - LinkedBlockingQueue - SynchronousQueue;
threadFactory:線程工廠,主要用來創建線程;
handler:表示當拒絕處理任務時的策略,有以下四種取值:
- ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。 - ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。 - ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程) - ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務
使用連接池應該做的事:
1. 調用Executors的靜態方法創建線程池。 2. 調用submit(),提交一個Callable對象或者Runnable對象。 3. 保存好獲得的Future<>對象,其中是計算結果(如果提交的是Callable)。 4. 沒有任何任務再提交的時候使用shutDown()。
public class TaskExercise { public static void main(String[] args) throws ExecutionException, InterruptedException { //future + callable ExecutorService executor = Executors.newCachedThreadPool(); CallTask callTask = new CallTask(); Future【控制任務組taskReturn = executor.submit(callTask); System.out.println(taskReturn.get()); //futureTask FutureTask futureTask = new FutureTask (callTask); executor.submit(futureTask); System.out.println(futureTask.get()); //runable Runnable runTask = new RunTask(); String result = "xz"; Future> runTaskReturn = executor.submit(runTask,result); System.out.println(runTaskReturn.get()); executor.shutdown(); } } class CallTask implements Callable { @Override public String call() throws Exception { return "task return"; } } class RunTask implements Runnable{ @Override public void run() { System.out.println("run"); } }
有時使用執行器更有意義的場景是控制一組相關任務。
1. shutdownNow():取消所有任務 2. invokeAny():提交所有對象到一個Callable對象集合,并返回某個已完成的任務結果。例如:如果你愿意接受任何一種解決方案的話。 3. 還有其他一些方法等我們真正用到時再學習好了~【補充
spring中實現異步調用:spring為任務調度與異步方法執行提供了注解支持。通過在方法上設置@Async注解,可使得方法被異步調用。也就是說調用者會在調用時立即返回,而被調用方法的實際執行是交給Spring的TaskExecutor來完成。如果是有返回值的話記得:接口返回Future<>,實現返回AsyncResult<>。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70902.html
摘要:創建線程的方式方式一將類聲明為的子類。將該線程標記為守護線程或用戶線程。其中方法隱含的線程為父線程?;謴途€程,已過時。等待該線程銷毀終止。更多的使當前線程在鎖存器倒計數至零之前一直等待,除非線 知識體系圖: showImg(https://segmentfault.com/img/bVbef6v?w=1280&h=960); 1、線程是什么? 線程是進程中獨立運行的子任務。 2、創建線...
摘要:某些編程語言被設計為可以將并發任務彼此隔離,這些語言通常被稱為函數性語言。通過使用多線程機制,這些獨立任務也被稱為子任務中的每一個都將由執行線程來驅動。 并發 之前學的都是順序編程的知識,學習并發編程就好像進入了一個全新的領域,有點類似于學習了一門新的編程語言,或者至少是學習了一整套新的語言概念。要理解并發編程,其難度與理解面向對象編程差不多。如果花點兒功夫,就能明白其基本機制,但想要...
摘要:相比與其他操作系統包括其他類系統有很多的優點,其中有一項就是,其上下文切換和模式切換的時間消耗非常少。因為多線程競爭鎖時會引起上下文切換。減少線程的使用。很多編程語言中都有協程。所以如何避免死鎖的產生,在我們使用并發編程時至關重要。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)syn...
摘要:因為多線程競爭鎖時會引起上下文切換。減少線程的使用。舉個例子如果說服務器的帶寬只有,某個資源的下載速度是,系統啟動個線程下載該資源并不會導致下載速度編程,所以在并發編程時,需要考慮這些資源的限制。 最近私下做一項目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Jav...
閱讀 1807·2023-04-26 02:14
閱讀 3729·2021-11-23 09:51
閱讀 1387·2021-10-13 09:39
閱讀 3976·2021-09-24 10:36
閱讀 3016·2021-09-22 15:55
閱讀 3524·2019-08-30 12:57
閱讀 2041·2019-08-29 15:30
閱讀 1988·2019-08-29 13:19