該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,若是能給各位看官帶來一絲啓發或者幫助,那真是極好的。java
上一篇說到了Android併發編程中的 原子類與併發容器,那麼本篇呢,繼續上一篇記錄一下Android併發編程中經常使用的一些工具類,以及面試必問知識點--線程池.面試
CountDownLatch容許一個或多個線程等待其餘線程完成操做。編程
當咱們須要用多個線程分解一些比較複雜任務時,這些任務一般符合下面兩個規則:多線程
用法:併發
public class CountDownLatchTest { static CountDownLatch c = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { System.out.println(1); c.countDown(); System.out.println(2); c.countDown(); } }).start(); c.await(); System.out.println("3"); } }
CountDownLatch的構造函數接收一個int類型的參數做爲計數器,若是你想等待N個點完成,這裏就傳入N。當咱們調用CountDownLatch的countDown方法時,N就會減1,CountDownLatch的await方法會阻塞當前線程,直到N變成零。框架
除了await()方法以外,也可使用另一個帶指定時間的await方法——await(long time,TimeUnit unit),這個方法等待特定時間後,就會再也不阻塞當前線程。異步
總結來講就是等待多個線程的完成,而後本身(調用await方法的線程)才運行.ide
同步屏障要作的事情是,讓一個線程到達一個屏障(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續運行。
用法函數
public class CyclicBarrierTest { static CyclicBarrier c = new CyclicBarrier(2); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { try { c.await(); } catch (Exception e) { } System.out.println(1); } }).start(); try { c.await(); } catch (Exception e) { } System.out.println(2); } }
CyclicBarrier默認的構造方法是CyclicBarrier(int parties),其參數表示屏障攔截的線程數
量,每一個線程調用await方法告訴CyclicBarrier我已經到達了屏障,而後當前線程被阻塞。當全部線程都到達了屏障時(即都調用了await方法)時,全部線程進行CPU競爭,由CPU調度運行.工具
Semaphore,信號量(令牌數).信號量這個概念跟咱們到一個很是火的飯店排隊領號吃飯同樣,因爲飯店的容量是有限的,只能容納N我的,前面N我的被叫到號進去用餐,其餘的人只能等待,直到飯店中有人離開,纔會繼續叫號.
Semaphore的構造方法Semaphore(int permits)接受一個整型的數字,表示可用的許可證數量。在上面的例子中這個數字就是飯店中能容納的人數.正在飯店內用餐的人表明正在運行的線程,在外面的等待的人表明阻塞的線程,吃完飯離開的人表明已經運行完畢的線程.
用法
public class SemaphoreTest { private static final int THREAD_COUNT = 30; private static ExecutorServicethreadPool = Executors .newFixedThreadPool(THREAD_COUNT); private static Semaphore s = new Semaphore(10); public static void main(String[] args) { for (inti = 0; i< THREAD_COUNT; i++) { threadPool.execute(new Runnable() { @Override public void run() { try { s.acquire(); System.out.println("save data"); s.release(); } catch (InterruptedException e) { } } }); } threadPool.shutdown(); } }
在代碼中,雖然有30個線程在執行,可是隻容許10個併發執行。Semaphore(10)表示容許10個線程獲取許可證,也就是最大併發數是10。
Semaphore使用Semaphore的acquire()方法獲取一個許可證,使用完以後調用release()方法歸還許可證。還能夠用tryAcquire()方法嘗試獲取許可證。
Java中的線程池是運用場景最多的併發框架,幾乎全部須要異步或併發執行任務的程序
均可以使用線程池。在開發過程當中,合理地使用線程池可以帶來3個好處。
Java中經常使用的線程池都是ThreadPoolExecutor不一樣的配置產生的以符合不一樣的場景.因此理解ThreadPoolExecutor相當重要.
下圖是線程池的原理模型.
有了線程池的原理模型以後,咱們再看在Java庫中是如何實現這個模型的,下面咱們來看ThreadPoolExecutor
FixedThreadPool被稱爲可重用固定線程數的線程池。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
FixedThreadPoolExecutor是一種線程數量固定的線程池,當線程處於空閒狀態時,它們並不會被回收,除非線程池被關閉了.當全部的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閒出來.因爲FixedThreadPool只有核心線程而且這些核心線程不會被回收,這意味着它可以更加快速的響應外界的請求.
SingleThreadExecutor是使用單個worker線程的Executor.
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
SingleThreadPool內部只有一個核心線程,它確保全部的任務都在同一個線程中按順序執行.
CachedThreadPool是一個會根據須要建立新線程的線程池。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
CachedThreadPool是一種線程數量不定的線程池,它只有非核心線程,而且其最大線程數Integer.MAX_VALUE是一個很大的數,實際上就至關於最大線程數能夠任意大.當線程池中的線程都處於活動狀態時,線程池會建立新的線程來處理新任務,不然就會利用空閒的線程來處理新任務.線程池中的空閒線程都有超時機制,60秒,超過60秒的的閒置線程就會被回收.
CachedThreadPoll比較適合執行大量的耗時較少的任務
ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor。它的核心線程數量是固定的,而非核心線程數是沒有限制的,而且當非核心線程閒置時會被當即回收.它主要用來在給定的延遲以後運行任務,或者按期執行任務。
本篇呢,記錄了一下併發編程中經常使用的一些工具類以及java或者Android面試中基本必問的只是點線程池.關於併發編程的記錄暫告一段落.後面可能會出番外篇.最近也入職了新公司,忙着適應新公司的時候好像怠慢了本身的積累.後面儘可能會按照一個月一篇的速度更新博客,感謝關注個人粉絲.
此致,敬禮