非同步&執行緒池
一、執行緒回顧
1、初始化執行緒的 4 種方式
- 繼承 Thread
- 實現 Runnable 介面
- 實現 Callable 介面 + FutureTask (可以拿到返回結果,可以處理異常)
- 執行緒池
public class ThreadTest { public static ExecutorService executorService = Executors.newFixedThreadPool(10); public static void main(String[] args) { /** * 1、繼承Thread * Thread01 thread01 = new Thread01(); * thread01.start();//啟動執行緒 * 2、實現Runnable * Runable01 runable01 = new Runable01(); * new Thread(runable01).start(); * 3、實現Callable介面 + FutureTask(可以拿到返回結果,可以處理異常) * FutureTask<Integer> futureTask = new FutureTask<>(new Callable01()); * new Thread(futureTask).start(); * Integer integer = futureTask.get(); * 4、執行緒池 * 任務直接提交至執行緒池。 * 區別: * 1、2不能得到返回值。3可以得到返回值 * 1、2、3不能控制資源 * 4、可以控制資源,效能穩定。*/ //123啟動執行緒方式都不用,原因是啟動執行緒不可控制,當執行緒過多時會導致資源浪費,系統崩潰的風險 //當前系統中保證執行緒池只有一兩個,每個非同步任務,提交給執行緒池去自己執行 executorService.execute(new Runable01()); } //繼承Thread public static class Thread01 extends Thread{ @Override public void run(){ System.out.println("當前執行緒:"+Thread.currentThread().getId());int i = 10/2; System.out.println("執行結果:"+i); } } //實現Runnable public static class Runable01 implements Runnable{ @Override public void run(){ System.out.println("當前執行緒:"+Thread.currentThread().getId()); int i = 10/2; System.out.println("執行結果:"+i); } } //實現Callable public static class Callable01 implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("當前執行緒:"+Thread.currentThread().getId()); int i = 10/2; return i; } } }
2、執行緒池的七大引數
* @param corePoolSize the number of threads to keep in the pool, even * if they are idle, unless {@code allowCoreThreadTimeOut} is set 池中一直保持的執行緒的數量,即使執行緒空閒。除非設定了 allowCoreThreadTimeOut * @param maximumPoolSize the maximum number of threads to allow in the * pool 池中允許的最大的執行緒數 * @param keepAliveTime when the number of threads is greater than * the core, this is the maximum time that excess idle threads * will wait for new tasks before terminating. 當執行緒數大於核心執行緒數的時候,執行緒在最大多長時間沒有接到新任務就會終止釋放, 最終執行緒池維持在 corePoolSize 大小 * @param unit the time unit for the {@code keepAliveTime} argument 時間單位 * @param workQueue the queue to use for holding tasks before they are* executed. This queue will hold only the {@code Runnable} * tasks submitted by the {@code execute} method. 阻塞佇列,用來儲存等待執行的任務,如果當前對執行緒的需求超過了 corePoolSize 大小,就會放在這裡等待空閒執行緒執行。 * @param threadFactory the factory to use when the executor * creates a new thread 建立執行緒的工廠,比如指定執行緒名等 * @param handler the handler to use when execution is blocked * because the thread bounds and queue capacities are reached 拒絕策略,如果執行緒滿了,執行緒池就會使用拒絕策略。
原生方式建立執行緒池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 200, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
執行流程:
1、執行緒池建立,準備好 core 數量的核心執行緒,準備接受任務
2、新的任務進來,用 core 準備好的空閒執行緒執行。
(1) 、core 滿了,就將再進來的任務放入阻塞佇列中。空閒的 core 就會自己去阻塞隊
列獲取任務執行
(2) 、阻塞佇列滿了,就直接開新執行緒執行,最大隻能開到 max 指定的數量
(3) 、max 都執行好了。Max-core 數量空閒的執行緒會在 keepAliveTime 指定的時間後自
動銷燬。最終保持到 core 大小
(4) 、如果執行緒數開到了 max 的數量,還有新任務進來,就會使用 reject 指定的拒絕策
略進行處理
3、所有的執行緒建立都是由指定的 factory 建立的。
面試:
一個執行緒池 core 7; max 20 ,queue:50,100 併發進來怎麼分配的;
先有 7 個能直接得到執行,接下來 50 個進入佇列排隊,在多開 13 個繼續執行。現在 70 個
被安排上了。剩下 30 個預設拒絕策略。
3、常見的 4 種執行緒池
- newCachedThreadPool
建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若
無可回收,則新建執行緒。
- newFixedThreadPool
建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
- newScheduledThreadPool
建立一個定長執行緒池,支援定時及週期性任務執行。
- newSingleThreadExecutor
建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務
按照指定順序(FIFO, LIFO, 優先順序)執行。
4、開發中為什麼使用執行緒池
- 降低資源的消耗
通過重複利用已經建立好的執行緒降低執行緒的建立和銷燬帶來的損耗
- 提高響應速度
因為執行緒池中的執行緒數沒有超過執行緒池的最大上限時,有的執行緒處於等待分配任務
的狀態,當任務來時無需建立新的執行緒就能執行
- 提高執行緒的可管理性
執行緒池會根據當前系統特點對池內的執行緒進行優化處理,減少建立和銷燬執行緒帶來
的系統開銷。無限的建立
二、CompletableFuture 非同步編排