一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android 并發(fā)二三事之Java線程池

 流浪的星星318 2017-06-05

最近在項(xiàng)目中接觸到了很多有關(guān)于多線程方面的東西,并且剛好前段時(shí)間看了Java并發(fā)編程實(shí)戰(zhàn)那本說,
所以想將自己所了解到的,以及實(shí)際中碰到的問題總結(jié)一下。

打算首先介紹一下,Java多線程相關(guān)的基礎(chǔ),例如Thread,Runnable。雖然這個(gè)極其的基礎(chǔ),但是我覺得任何東西都
繞不過基礎(chǔ)的知識(shí)。重點(diǎn)會(huì)在介紹線程池,包括線程池相關(guān)類的層級(jí)結(jié)構(gòu)、相關(guān)參數(shù)等。
以及在Android中有那些多線程表現(xiàn)形式,例如:AsyncTask,HandlerThread,IntentService, AsycTaskLoader等。
之后希望能簡單的表述一下多線程與Future, TimeUnit , CountDownLatch 等等相關(guān)類的關(guān)系,以及如何在子線程中如何開啟子線程去請求數(shù)據(jù),子線程與主線程如何交互數(shù)據(jù)等。
還有就是介紹多線程相關(guān)概念,鎖, 可重入鎖, 死鎖, 如何排查死鎖, 線程發(fā)布, 競態(tài)條件, 數(shù)據(jù)競爭 等等

應(yīng)該會(huì)分幾篇博客來總結(jié)相關(guān)的知識(shí)。當(dāng)然其中肯定會(huì)有一些錯(cuò)誤之處,歡迎留言指出。我會(huì)及時(shí)更正。

以上相關(guān)所有知識(shí)點(diǎn),有許多借鑒自其他的大神的博客,由于看了許多,沒辦法一一列舉,在此表示感謝。許多概念相關(guān)的知識(shí)來自于《Java并發(fā)編程實(shí)戰(zhàn)》那本書。

一、Thread 繼承Thread類,重寫run方法。

我覺得Thread應(yīng)該是被最經(jīng)常用到的。當(dāng)只需要一個(gè)簡單的線程,不需要管理線程時(shí)直接:

new Thread(){
            @Override
            public void run() {
        //請求網(wǎng)絡(luò)等
            }
    }.start();123456123456

一個(gè)匿名內(nèi)部類就寫完了,相信很多人都寫過這樣的代碼。需要注意的是,如果在Activity中寫這樣的代碼很容易造成內(nèi)存泄露。
即當(dāng)Activity結(jié)束時(shí),線程的工作還沒有做完,這就會(huì)導(dǎo)致該Activity不會(huì)被回收??梢钥紤]用靜態(tài)內(nèi)部類的形式代替上面的寫法。

二、 Runnable 實(shí)現(xiàn)Runnable接口重寫run()方法

public class DisableRunnable implements Runnable{

        @Override
        public void run() {
            //請求網(wǎng)絡(luò)等
        }
    }12345671234567

Runnable 是執(zhí)行任務(wù)的單元,需要用Thread包裝一下才可以執(zhí)行。
Runnable 接口在Android中的使用也非常的多.例如View.post(),Handler.post()等等。

每當(dāng)我們看到這樣的代碼時(shí):

new Thread(){runnable}.start();

當(dāng)你考慮用更靈活的策略來執(zhí)行任務(wù)時(shí),可以考慮利用線程池代替Thread。

三、 線程池:

下面主要說一下線程池相關(guān)的總結(jié),
線程池結(jié)構(gòu):

最頂層接口 Executor

public interface Executor {

    void execute(Runnable command);

}1234512345

ExecutorService接口 繼承Executor 定義了一些有關(guān)于生命周期的方法。

public interface ExecutorService extends Executor {

    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}123456789101112131415161718192021222324252627282930123456789101112131415161718192021222324252627282930

ThreadPoolExecutor 間接實(shí)現(xiàn)了ExecutorService 是真正做事的線程池。最常見的幾種線程池都是它的實(shí)現(xiàn)。

ThreadPoolExecutor 常用的構(gòu)造方法:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler){}123456123456

相關(guān)參數(shù)解釋:
corePoolSize 核心線程池大小
maximumPoolSize 最大線程池大小
keepAliveTime 線程池中超過corePoolSize數(shù)目的空閑線程最大存活時(shí)間;可以allowCoreThreadTimeOut(true)使得核心線程有效時(shí)間
TimeUnit keepAliveTime時(shí)間單位
workQueue 阻塞任務(wù)隊(duì)列
RejectedExecutionHandler 飽和策略 當(dāng)提交任務(wù)數(shù)超過maxmumPoolSize+workQueue之和時(shí),任務(wù)會(huì)交給RejectedExecutionHandler來處理

1.當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),即使此時(shí)線程池中存在空閑線程。
2.當(dāng)線程池達(dá)到corePoolSize時(shí),新提交任務(wù)將被放入workQueue中,等待線程池中任務(wù)調(diào)度執(zhí)行
3.當(dāng)workQueue已滿,且maximumPoolSize>corePoolSize時(shí),新提交任務(wù)會(huì)創(chuàng)建新線程執(zhí)行任務(wù)
4.當(dāng)提交任務(wù)數(shù)超過maximumPoolSize時(shí),新提交任務(wù)由RejectedExecutionHandler處理
5.當(dāng)線程池中超過corePoolSize線程,空閑時(shí)間達(dá)到keepAliveTime時(shí),關(guān)閉空閑線程

注意:
這里maximumPoolSize 指的是corePoolSize + 由于隊(duì)列已滿并且maximumPoolSize>corePoolSize時(shí),為執(zhí)行任務(wù)創(chuàng)建的線程數(shù)。
所以第4條應(yīng)該說成,當(dāng)workQueue已滿,并且線程池內(nèi)的線程數(shù)已經(jīng)達(dá)到了maximumPoolSize最大線程數(shù)。這時(shí),再次提交任務(wù)會(huì)交給RejectedExecutionHandler 飽和策略去處理。

四、這里BlockingQueue
可以為:SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue 等等。
我們需要先了解這幾個(gè)隊(duì)列,當(dāng)清楚這些隊(duì)列的性質(zhì)后,再去看那幾個(gè)常用的線程池,將會(huì)非常容易理解。

SynchronousQueue
SynchronousQueue 首先它是無界的,也就是說它存儲(chǔ)的能力是沒有限制的。
但是它每一個(gè)put操作必須等待一個(gè)take操作。也就是說在某一次添加元素后,必須要等其他線程將它取走,否則不能添加。

LinkedBlockingQueue
LinkedBlockingQueue 無界隊(duì)列,也就是說使用LinkedBlockingQueue時(shí),當(dāng)所有corePoolSize都在忙時(shí),新任務(wù)都會(huì)在LinkedBlockingQueue中等待。
因?yàn)長inkedBlockingQueue是無界的(最大長度為Integer.MAX_VALUE,這里認(rèn)為無界)。這個(gè)時(shí)候maximumPoolSize其實(shí)就無效了,因?yàn)橹挥挟?dāng)LinkedBlockingQueue已滿時(shí),才會(huì)創(chuàng)建新的線程執(zhí)行任務(wù)。而這里L(fēng)inkedBlockingQueue永遠(yuǎn)都不會(huì)滿。所以maximumPoolSize也就無效了,也就是說利用這個(gè)隊(duì)列構(gòu)造的線程池,永遠(yuǎn)也不會(huì)創(chuàng)建新的線程。

ArrayBlockingQueue
ArrayBlockingQueue 有界隊(duì)列 可以設(shè)置隊(duì)列的大小,能夠有效的防止資源消耗。但是者也就導(dǎo)致這種情況控制起來會(huì)相對復(fù)雜,JDK建議的幾種常見的線程池都沒有使用這個(gè)隊(duì)列。

PriorityBlockingQueue 優(yōu)先級(jí)隊(duì)列

Executors 線程池工具類,用于生產(chǎn)線程池。

五、幾類比較常見的線程池:

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

解釋:構(gòu)建一個(gè)固定數(shù)目的線程池。corePoolSize 與 maximumPoolSize 數(shù)值相等。當(dāng)線程池中沒有空閑線程時(shí),利用 LinkedBlockingQueue
保存阻塞任務(wù),因?yàn)橹耙呀?jīng)說過了 LinkedBlockingQueue 是無界的,也就是說這個(gè)隊(duì)列永遠(yuǎn)不會(huì)滿,那maximumPoolSize 其實(shí)就沒有任何意義。

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

解釋:構(gòu)建一個(gè)單線程(只有一個(gè)線程,單不一定是同一個(gè)線程)的線程池。corePoolSize 與 maximumPoolSize 均為1 .利用無界的LinkedBlockingQueue 作為保存任務(wù)的隊(duì)列,這樣就保證無論提交多少個(gè)人物,線程池只能有一個(gè)線程在運(yùn)行,其余的任務(wù)均保存在 LinkedBlockingQueue 隊(duì)列中。

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }1234512345

解釋:構(gòu)建一個(gè)具有緩存功能的線程池,corePoolSize = 0, maximumPoolSize = Integer.MAX_VALUE 。隊(duì)列用的是SynchronousQueue。每加入一個(gè)任務(wù),線程池便會(huì)構(gòu)建一個(gè)線程將它取出執(zhí)行(如果有空閑的線程,會(huì)利用空閑的線程,而不會(huì)創(chuàng)建新的線程),這樣,加入多少個(gè)任務(wù)便會(huì)創(chuàng)建相同個(gè)數(shù)的線程。所以這個(gè)線程池的 maximumPoolSize 為Integer.MAX_VALUE。這就保證了線程池的最大線程數(shù)是無界的,理論上線程池可以有任意個(gè)線程。當(dāng)線程執(zhí)行完任務(wù)后,超過60秒的空閑時(shí)間即被回收銷毀。

六、飽和策略:

RejectedExecutionHandler 參數(shù)用來表示飽和策略。即表示當(dāng)有界隊(duì)列已滿,并且當(dāng)前線程池中的線程數(shù)已達(dá)到 maximumPoolSize ,這時(shí)再提交任務(wù),會(huì)交給RejectedExecutionHandler 來處理。

注意:這里一定是有界隊(duì)列,因?yàn)闊o界隊(duì)列我們認(rèn)為是永遠(yuǎn)也無法填滿的(SynchronousQueue直接由生產(chǎn)者提交給工作線程),那么也就永不到飽和策略了。

public interface RejectedExecutionHandler {

    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);

}1234512345

RejectedExecutionHandler 本身是一個(gè)接口。在Executors中提供了幾個(gè)實(shí)現(xiàn)類。

1)AbortPolicy:中止,executor拋出未檢查RejectedExecutionException,調(diào)用者捕獲這個(gè)異常,然后自己編寫能滿足自己需求的處理代碼。

2)DiscardRunsPolicy:遺棄最舊的,選擇丟棄的任務(wù),是本應(yīng)接下來就執(zhí)行的任務(wù)。

3)DiscardPolicy:遺棄會(huì)默認(rèn)放棄最新提交的任務(wù)(這個(gè)任務(wù)不能進(jìn)入隊(duì)列等待執(zhí)行時(shí))

4)CallerRunsPolicy:調(diào)用者運(yùn)行,既不會(huì)丟棄哪個(gè)任務(wù),也不會(huì)拋出任何異常,把一些任務(wù)推回到調(diào)用者那里,以此減緩新任務(wù)流。它不會(huì)在池線程中執(zhí)行最新提交的任務(wù),但它會(huì)在一個(gè)調(diào)用了execute的線程中執(zhí)行。

七、線程工廠:
線程池另外還有一個(gè)參數(shù)便是:ThreadFactory。之前在介紹常用的構(gòu)造方法沒有說它的原因是,一般用不到。其他構(gòu)造方法中都給出了默認(rèn)實(shí)現(xiàn):DefaultThreadFactory。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {}

public interface ThreadFactory {

    Thread newThread(Runnable r);

}1234567891011121312345678910111213

ThreadFactory 在 Executors 中也提供了幾個(gè)實(shí)現(xiàn)類,一般博主所接觸過的都是 DefaultThreadFactory 。當(dāng)然我們可以自己定制,
用于添加一些Log等等。之前推薦的幾種線程池都有 ThreadFactory 作為參數(shù)的方法。

八、常見的線程池的使用:

自定義線程池:

private final static ExecutorService executorService = new ThreadPoolExecutor(
            5,
            10,
            30L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(),
            new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    //DO nothing
                }
            });123456789101112123456789101112

這里我們用的是自定義的線程池。我們定義了一個(gè)核心線程池為5的線程池,線程池內(nèi)最大的線程池?cái)?shù)為10。

當(dāng)然由于我們這里定義的緩存隊(duì)列為LinkedBlockingQueue, 沒有制定隊(duì)列大小,那么其默認(rèn)無Integer.MAX_VALUE。
也就是無限大,所以最大線程數(shù)沒有用處。

飽和策略也是自定的,這里當(dāng)達(dá)到執(zhí)行飽和策略時(shí),什么都不做,直接丟棄。

public void request() {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    //請求網(wǎng)絡(luò)等。
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }


利用Executors 提供的線程池:

public void request() {

        ExecutorService executor = Executors.newFixedThreadPool(5);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    //請求網(wǎng)絡(luò)等。
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

    }1234567891011121314151617181920212223242526272829303112345678910111213141516171819202122232425262728293031

OK, 線程池相關(guān)就介紹到這里,下一篇會(huì)介紹Future,FutureTask, Callable 等等相關(guān)知識(shí)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    激情五月天免费在线观看| 人妻一区二区三区在线| 深夜福利欲求不满的人妻| 色婷婷亚洲精品综合网| 精品国产成人av一区二区三区| 亚洲综合色在线视频香蕉视频| 午夜视频免费观看成人| 日本办公室三级在线观看| 久久综合狠狠综合久久综合| 日本少妇中文字幕不卡视频 | 亚洲精品一区二区三区日韩| 殴美女美女大码性淫生活在线播放 | 日韩中文字幕视频在线高清版| 色偷偷偷拍视频在线观看| 日本东京热加勒比一区二区| 中文字幕一区二区久久综合| 亚洲中文字幕人妻av| 国产精品欧美日韩中文字幕| 国产91人妻精品一区二区三区| 国产亚洲二区精品美女久久| 亚洲国产一级片在线观看| 成人日韩在线播放视频| 国产高清在线不卡一区| 欧美自拍系列精品在线| 一区二区三区亚洲国产| 亚洲国产精品久久精品成人| 免费特黄欧美亚洲黄片| 午夜久久精品福利视频| 日本本亚洲三级在线播放| 亚洲中文字幕熟女丝袜久久| 激情视频在线视频在线视频 | 亚洲国产精品一区二区毛片| 欧美一级不卡视频在线观看| 久久青青草原中文字幕| 亚洲第一香蕉视频在线| 精品亚洲av一区二区三区| 欧美日不卡无在线一区| 久久国产精品热爱视频| 91蜜臀精品一区二区三区| 亚洲欧美视频欧美视频| 亚洲熟妇熟女久久精品 |