Android 併發工具類與線程池

該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,若是能給各位看官帶來一絲啓發或者幫助,那真是極好的。java


前言

上一篇說到了Android併發編程中的 原子類與併發容器,那麼本篇呢,繼續上一篇記錄一下Android併發編程中經常使用的一些工具類,以及面試必問知識點--線程池.面試

併發工具類

CountDownLatch(等待多線程完成)

CountDownLatch容許一個或多個線程等待其餘線程完成操做。編程

當咱們須要用多個線程分解一些比較複雜任務時,這些任務一般符合下面兩個規則:多線程

  1. 任務能夠分解爲多個相互獨立的子任務
  2. 全部子任務的綜合結果即爲該任務的結果

用法:併發

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

CyclicBarrier(同步屏障)

同步屏障要作的事情是,讓一個線程到達一個屏障(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續運行。
用法函數

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(控制線程數量)

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個好處。

  1. 下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
  2. 提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。
  3. 提升線程的可管理性。線程是稀缺資源,若是無限制地建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一分配、調優和監控。可是,要作到合理利用線程池,必須對其實現原理了如指掌。

Java中經常使用的線程池都是ThreadPoolExecutor不一樣的配置產生的以符合不一樣的場景.因此理解ThreadPoolExecutor相當重要.
下圖是線程池的原理模型.

線程池模型

有了線程池的原理模型以後,咱們再看在Java庫中是如何實現這個模型的,下面咱們來看ThreadPoolExecutor

ThreadPoolExecutor

圖片描述

Java的經常使用線程池

FixedThreadPoolExecutor

FixedThreadPool被稱爲可重用固定線程數的線程池。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
}

FixedThreadPoolExecutor是一種線程數量固定的線程池,當線程處於空閒狀態時,它們並不會被回收,除非線程池被關閉了.當全部的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閒出來.因爲FixedThreadPool只有核心線程而且這些核心線程不會被回收,這意味着它可以更加快速的響應外界的請求.

SingleThreadExecutor詳解

SingleThreadExecutor是使用單個worker線程的Executor.

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>()));
}

SingleThreadPool內部只有一個核心線程,它確保全部的任務都在同一個線程中按順序執行.

CachedThreadPool

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

ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor。它的核心線程數量是固定的,而非核心線程數是沒有限制的,而且當非核心線程閒置時會被當即回收.它主要用來在給定的延遲以後運行任務,或者按期執行任務。


本篇總結

本篇呢,記錄了一下併發編程中經常使用的一些工具類以及java或者Android面試中基本必問的只是點線程池.關於併發編程的記錄暫告一段落.後面可能會出番外篇.最近也入職了新公司,忙着適應新公司的時候好像怠慢了本身的積累.後面儘可能會按照一個月一篇的速度更新博客,感謝關注個人粉絲.


此致,敬禮

相關文章
相關標籤/搜索