>原創宣告:本文來源於公眾號【胖滾豬學程式設計】,轉載請註明出處。 上一節[【漫畫】JAVA併發程式設計三大Bug源頭(可見性、原子性、有序性)](https://mp.weixin.qq.com/s?__biz=MzA3MjY1MTcyNw==&mid=2247484235&idx=1&sn=441293013d4e5430c3146acdfb511351&chksm=9f1a45eba86dccfd9dc80c1ebb28b8ee44694abe01ef79583c6b95ad12bdf52ec530db89fd3b&token=281460280&lang=zh_CN#rd)我們聊了聊併發程式設計的三個bug源頭,這還沒開始進入併發世界,胖滾豬就遇到了難題。。 這個難題是所有初學者都會有的疑惑:沒法復現那些理論知識告訴我們的bug。但是實際操練很重要,那麼在本地開發環境,到底應該怎樣模擬併發呢? ![_1](https://yqfile.alicdn.com/7d4a47407e5ead8dde0647f84aaadc1984c87ca1.jpeg) # 模擬併發工具大全 在本地模擬併發環境的方法有挺多的,比較熱門的有以下幾種,包括工具和程式碼: 1、Postman:Http請求模擬工具,可以設定發起N個請求(但不推薦,並不專業) 2、Apache Bench(AB):Apache 伺服器的一個web壓力測試工具,是一個命令列工具,可根據命令建立很多併發訪問執行緒,模擬多個訪問者同時對某一個URL地址進行訪問。總體來說,ab工具小巧簡單,上手學習較快,可以提供需要的基本效能指標;但是缺點就是沒有圖形化結果,不能監控。 3、Apache JMeter:Apache組織開發的基於Java的壓力測試工具。功能相比AB會更加強大,尤其是有GUI圖形化介面,這一點很爽。另外jmeter是一次完整的請求和返回;AB只是發出去請求,並不對返回做處理。如果你希望看到返回結果,那麼也應該選擇JMeter。 4、JAVA程式碼:包括CountDownLatch、CyclicBarrier等 我們主要說一下如何通過jmeter和程式碼來模擬併發環境,也推薦使用這兩種方式。 # CountDownLatch(等待多執行緒完成) >原創宣告:本文來源於公眾號【胖滾豬學程式設計】,轉載請註明出處。 countDownLatch是在java1.5被引入,存在於java.util.cucurrent包下。 這個類能使**一個執行緒等待其他執行緒各自執行完畢後再執行**。 **它是通過一個計數器來實現的,計數器的初始值是執行緒的數量。每當一個執行緒執行完畢後,計數器的值就-1,當計數器的值為0時,表示所有執行緒都執行完畢,然後在閉鎖上等待的執行緒就可以恢復工作了。** 如圖所示,初始值cnt=3,執行緒A執行了await方法所以被阻塞等待,T1\T2\T3執行緒通過呼叫countDown,讓計數器減一,直到cnt=0後,Thread A才恢復執行。換句話說就是,Thread A需要等待其他三個執行緒都執行完才能執行: ![image](https://yqfile.alicdn.com/5ad793ce41c3f7dfc71f77ab8bef39cc1a3629cf.png) countDownLatch類中只提供了一個構造器: ``` //引數count為計數值 public CountDownLatch(int count) { }; countDownLatch類中有三個方法是最重要的: ``` //呼叫await()方法的執行緒會被掛起,它會等待直到count值為0才繼續執行 ``` public void await() throws InterruptedException { }; //和await()類似,只不過等待一定的時間後count值還沒變為0的話就會繼續執行 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //將count值減1 public void countDown() { }; ``` 舉例:需求是處理一個Excel,Excel有很多行資料,為了效率,我們可以使用多執行緒處理,但是處理完所有行資料後,需要通知到主執行緒。如果沒有countDownLatch,那麼效果是這樣的,還沒處理完呢你就說我結束了: ![image](https://yqfile.alicdn.com/0cbf17a32c9de9f4be5c6ac131cf4e401f5088e6.png) 如果在主執行緒上加上countDownLatch,並且呼叫await()方法,那麼主執行緒會被掛起,它會等待直到count值為0才繼續執行: ``` static CountDownLatch countDownLatch = new CountDownLatch(100); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 100; i++) { Thread thread = new Thread(() -> { doWork(); countDownLatch.countDown(); }); thread.start(); } countDownLatch.await(); System.out.println("處理完整個excel的結束時間"+System.currentTimeMillis()); } public static void doWork(){ System.out.println("處理行資料,時間"+System.currentTimeMillis()); } ``` ![_2](https://yqfile.alicdn.com/07463bc34e2967b629b1c0b041388ba08e80e2ee.jpeg) ``` Thread thread = new Thread(() -> { try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } doWork(); }); thread.start(); countDownLatch.countDown(); ``` ![_3](https://yqfile.alicdn.com/8785a97b1338442612e2aab0ffa335ddcf25aa5a.jpeg) **執行緒池** ``` ExecutorService executorService = new ThreadPoolExecutor(100, 200, 60, TimeUnit.MINUTES, new ArrayBlock