繼上一次講的開始說吧。
new ThreadPoolExecutor() 自定義參數,理解每個參數什麼含義,具體到某些業務場景,還要看具體怎麼用。在此,再解釋下核心線程數跟最大線程數到底有什麼作用。舉個例子:
new ThreadPoolExecutor(1,2,60,TimeUnit.Days,ArrayBlockingQueue),這個ArrayBlockingQueue = new ArrayBlockingQueue(4),某個業務場景,需要執行7個sql,交給了ThreadExecutor來執行,ThreadExecutor 核心線程數只有1個,所以ThreadExecutor會執行第一個sql,這時候沒執行完,剩下的6個sql 會放到queue中,由於ArrayBlockingQueue是個有界隊列,最多隻會放下4個任務, (LinkedBlockingQueue是無界隊列,所以想放多少任務都可以),剩下兩個任務,ThreadPoolExecutor 會用 max線程數-核心線程數,直接new 對象去執行。上面例子,因爲最多有2個線程,核心線程只有一個,所以還有一個線程,程序發現,我線程不夠用啊,因爲還有兩個子任務,那我就報錯吧。
demo:
public class UseThreadExecutorPool implements Runnable { private static AtomicInteger count = new AtomicInteger(); @Override public void run() { int all = count.incrementAndGet(); System.out.println(all); } //自定義線程池 各個參數什麼意思 corePoolSize 核心線程數,maximumPoolSize 最大線程數, //當 任務數量 <= corePoolSize 直接執行, 當 maximumPoolSize =>任務數量 > corePoolSize ,任務數量-corePoolSize 的任務 加到queue裏面,拿corePoolSize 線程執行, //當 maximumPoolSize < 任務數量 在不超過 maximumPoolSize的情況下 新建線程執行 加滿queue之後的 任務,當超過了最大線程數,就報錯, public static void main(String[] args) { ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<UseThreadExecutorPool>(4); ExecutorService executorService = new ThreadPoolExecutor(1, 2, 60, TimeUnit.DAYS, arrayBlockingQueue); UseThreadExecutorPool useThreadExecutorPool0 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool1 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool2 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool3 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool4 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool5 = new UseThreadExecutorPool(); UseThreadExecutorPool useThreadExecutorPool6 = new UseThreadExecutorPool(); executorService.execute(useThreadExecutorPool0); executorService.execute(useThreadExecutorPool1); executorService.execute(useThreadExecutorPool2); executorService.execute(useThreadExecutorPool3); executorService.execute(useThreadExecutorPool4); executorService.execute(useThreadExecutorPool5); executorService.execute(useThreadExecutorPool6); executorService.shutdown(); } },當然呢,這個錯誤是可以自己處理的,詳細看上一篇博客。
-----------------------------------------------------------------------------
下面談談CyclicBarrier 、CountDownLatch 和 信號量。
先說下CyclicBarrier 和CountDownLatch吧。這倆都可以實現實時通知,類似於分佈式的並行計算,區別就是CyclicBarrier 是喚起多個線程,CountDownLatch喚起一個線程,舉例個業務場景,運動五個跑步選手比賽,發令槍沒響之前,各自幹各自的事,喝水啊,綁鞋帶啊,但是喊準備的時候,就統一聽發令員的槍聲了,下面看下例子
public class UseCyclicbarrier { static class Runner implements Runnable { private CyclicBarrier barrier; private String name; public Runner(CyclicBarrier barrier, String name) { this.barrier = barrier; this.name = name; } @Override public void run() { try { Thread.sleep(5000); System.out.println(name + " 準備好了 "); barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(name + "go"); } } public static void main(String[] args) { CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(barrier, "小明"))); executor.submit(new Thread(new Runner(barrier, "小白"))); executor.execute(new Thread(new Runner(barrier, "小紅"))); executor.shutdown(); } }CyclicBarrier 初始化後面寫個3,意思就是對象得調用三次await()方法,才能一同喚起,做自己的操作,兩個就不行,會一直等待。三個線程都準備好了,才一起開始。這就是CyclicBarrier 。記住,CyclicBarrier 是喚起子線程,下面講的CountDownLatch 是喚起一個線程,類似於統計的操作,舉個CountDownLatch的demo
public class UseCountDownLatch { public static void main(String[] args) { final CountDownLatch countDownLatch = new CountDownLatch(2); Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("進入t1 等待其他線程執行完畢"); try { countDownLatch.await(); System.out.println("執行完畢"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("進入t2 "); try { countDownLatch.countDown(); } catch (Exception e) { e.printStackTrace(); } } }); Thread t3 = new Thread(new Runnable() { @Override public void run() { System.out.println("進入t3 "); try { countDownLatch.countDown(); } catch (Exception e) { e.printStackTrace(); } } }); t1.start(); t2.start(); t3.start(); } }可以把代碼粘貼到自己的編輯器裏面,自己慢慢體會這兩者的區別
信號量:說到信號量,不得不說的一個詞叫分流,限流,這是在應用架構中經常性聽到的詞,什麼意思呢,就是一個應用系統最大能承受10個客戶,當前有20個客戶,可以從網絡層限制,也可以從服務層限制,還可以從java層面去限制,java層面就是用的信號量,信號量可以定義當前可以處理多少個請求,達到分流的效果。服務層呢可以用nginx做分流,限流。網絡層的話 類似於cdn做鏡像,這也是分流,限流的一種策略。代碼不展示了,百度下一堆,知道什麼意思就行。
下面說說英文單詞;
pv:每個頁面的訪問量,不計算單個ip,刷新一個即計數。
uv:最小請求單位(ip,每天只統計一次)
qps(tps):每秒請求數
rt:每個request請求的返回時間。
這些名詞,有可能在做自動化測試的時候提到。
----------------------------------------------------------------------------------------
下面說說 重入鎖 跟 讀寫鎖:也就是Lock 跟RetreentLock,這兩者與sync 有什麼區別呢,1.8以前sync性能不太好,1.8以後沒區別,如果非要問1.8以後的區別的話,Lock鎖更加簡單化,隨性化。RetreentLock 試用場景 讀多寫少 ,讀少寫多的話可以使用RetreentReadWriteLock 代碼不展示,
還有兩個鎖是 readLock 跟 writeLock。記住一個方言就是,讀讀共享,讀寫互斥,寫寫互斥。
下篇博客談談disruptor併發框架。(一個很nb的併發框架)