1. 程式人生 > >android 執行緒池的使用以及Executors的優缺點

android 執行緒池的使用以及Executors的優缺點

android開發,大家最熟悉的肯定是主執行緒,也就是ui執行緒,也都知道在非ui執行緒更新介面會報錯提示不允許在子執行緒更新ui。但是耗時操作還是需要使用子執行緒,例如:

new Thread(new Runnable() {
    @Override
    public void run() {
        // TODO Auto-generated method stub
    }
}).start();

感覺方便直接,在任務結束後GC也會自動回收該執行緒,不過它還在存在很大的弊端

  1. 如果某個地方需要開啟大量的執行緒。建立執行緒和銷燬執行緒是需要時間的,這樣會導致效能不足
  2. 執行緒無法管理,相互競爭導致卡頓或者oom
  3. 功能太過單一

所以針對這些問題,我們需要重用執行緒,使用執行緒池。

執行緒池:ThreadPoolExecutor
先來看看建構函式:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corepoolsize:核心執行緒數
  • maximumPoolSize:最大執行緒數
  • keepAliveTime:執行緒空閒時間
  • unit:keepAliveTime的時間單位
  • workQueue:阻塞任務佇列
  • threadFactory:新建執行緒工廠
  • RejectedExecutionHandler:當提交當提交任務數超過maxmumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理

配置起來還是比較繁瑣,所以官方提供了一個類Executors來幫助我們迅速建立我們需要的執行緒池,比較常見的有:

1:newFixedThreadPool() :


該方法返回一個固定執行緒數量的執行緒池,該執行緒池中的執行緒數量始終不變,即不會再建立新的執行緒,也不會銷燬已經建立好的執行緒,自始自終都是那幾個固定的執行緒在工作,所以該執行緒池可以控制執行緒的最大併發數。 超出的執行緒會在佇列中等待。
2:newCachedThreadPool:
該方法返回一個可以根據實際情況調整執行緒池中執行緒的數量的執行緒池。如果沒有執行緒不夠用則會一直建立,有空閒執行緒則會複用。
3:newSingleThreadExecutor() :
顧名思義,返回只有一個執行緒的執行緒池。多餘的任務會存在佇列中等待執行
4:newScheduledThreadPool():
返回一個可以固定執行緒個數和設定執行緒延遲執行時間,執行週期 的執行緒池

好了,來看下具體使用方式:

newFixedThreadPool

ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 100; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    Log.i("thread", Thread.currentThread().getName());
                }
            });
        }

規定執行緒數為3,然後迴圈執行列印執行緒名字

12-06 16:29:06.665 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15257/? I/thread: pool-1-thread-2
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15258/? I/thread: pool-1-thread-3
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15257/? I/thread: pool-1-thread-2
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15257/? I/thread: pool-1-thread-2
12-06 16:29:06.667 15218-15258/? I/thread: pool-1-thread-3
12-06 16:29:06.667 15218-15257/? I/thread: pool-1-thread-2
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15257/? I/thread: pool-1-thread-2
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15258/? I/thread: pool-1-thread-3
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1
12-06 16:29:06.667 15218-15258/? I/thread: pool-1-thread-3
12-06 16:29:06.667 15218-15256/? I/thread: pool-1-thread-1

可以看出始終只有三個執行緒在跑任務,符合預期

newCachedThreadPool

ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    Log.i("thread", Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

程式碼差不多,加了一個睡眠時間模擬處理時間,看看控制檯部分輸出:

12-06 16:33:28.463 15429-15454/? I/thread: pool-1-thread-11
12-06 16:33:28.463 15429-15456/? I/thread: pool-1-thread-13
12-06 16:33:28.464 15429-15457/? I/thread: pool-1-thread-14
12-06 16:33:28.464 15429-15458/? I/thread: pool-1-thread-15
12-06 16:33:28.464 15429-15455/? I/thread: pool-1-thread-12
12-06 16:33:28.464 15429-15468/? I/thread: pool-1-thread-25
12-06 16:33:28.464 15429-15469/? I/thread: pool-1-thread-26
12-06 16:33:28.465 15429-15470/? I/thread: pool-1-thread-27
12-06 16:33:28.465 15429-15471/? I/thread: pool-1-thread-28
12-06 16:33:28.466 15429-15472/? I/thread: pool-1-thread-29
12-06 16:33:28.466 15429-15474/? I/thread: pool-1-thread-30
12-06 16:33:28.467 15429-15476/? I/thread: pool-1-thread-32
12-06 16:33:28.467 15429-15475/? I/thread: pool-1-thread-31
12-06 16:33:28.467 15429-15477/? I/thread: pool-1-thread-33
12-06 16:33:28.467 15429-15478/? I/thread: pool-1-thread-34
12-06 16:33:28.468 15429-15479/? I/thread: pool-1-thread-35
12-06 16:33:28.469 15429-15480/? I/thread: pool-1-thread-36
12-06 16:33:28.469 15429-15481/? I/thread: pool-1-thread-37
12-06 16:33:28.469 15429-15482/? I/thread: pool-1-thread-38
12-06 16:33:28.471 15429-15484/? I/thread: pool-1-thread-40
12-06 16:33:28.471 15429-15483/? I/thread: pool-1-thread-39

因為睡眠時間長導致每次迴圈都建立一個執行緒,如果取消sleep時間會看到執行緒數量沒有這麼多,因為會複用。

newSingleThreadExecutor

ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 100; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    Log.i("thread", Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

還是差不多的程式碼,看控制檯輸出

12-06 16:36:30.480 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:31.481 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:32.481 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:33.482 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:34.482 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:35.483 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:36.483 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:37.484 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:38.484 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:39.484 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:40.485 15693-15708/? I/thread: pool-1-thread-1
12-06 16:36:41.485 15693-15708/? I/thread: pool-1-thread-1

可以看出每次都是同一個執行緒在執行,所有任務在排隊執行

newScheduledThreadPool

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
executorService.schedule(new Runnable() {
            @Override
            public void run() {
                Log.i("thread", Thread.currentThread().getName());
            }
        }, 3000, TimeUnit.MILLISECONDS);

延遲執行,schedule第二三個方法執行時間長度和時間單位

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Log.i("thread", Thread.currentThread().getName());
            }
        }, 5000,3000, TimeUnit.MILLISECONDS);

週期性執行,延遲5秒後,每隔3秒執行一次,按照任務開始計算,然後任務執行時間大於間隔時間,則會在任務結束後立馬執行下一次。scheduleWithFixedDelay會在任務結束後開始計算間隔時間,和任務執行時間無關.

簡單介紹了一下好處,也得來講講這種簡單建立執行緒池的方式的缺點:
newFixedThreadPool和newSingleThreadExector:
主要問題是推擠的請求處理佇列可能會耗費非常大的記憶體,甚至導致oom。
newCachedThreadPool和newScheduledThreadPool:
主要問題是執行緒數沒有限制,可能會建立數量非常多的執行緒,導致oom

相關推薦

android 執行的使用以及Executors優缺點

android開發,大家最熟悉的肯定是主執行緒,也就是ui執行緒,也都知道在非ui執行緒更新介面會報錯提示不允許在子執行緒更新ui。但是耗時操作還是需要使用子執行緒,例如: new Thread(new Runnable() { @Override

JAVA執行--Executors之什麼是執行,為什麼使用執行以及執行的使用

1. 為什麼需要執行緒池?      多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。              假設一個伺服器完成一項任務所需時間為:T1 建立執行緒時間,T2 線上程中執行任務的時間,T

Android執行學習

在學習執行緒池之前需要先了解幾個java的執行緒池 1.newCachedThreadPool   建立一個可快取執行緒池,根據長度靈活回收,若無空閒執行緒,則新建執行緒 2.newFixedThreadPool  建立一個定長執行緒池,可控制執行緒最大併

簡述Java執行以及使用

建立執行緒的幾種方式 繼承Thread,重寫run()方法 實現Runnable介面,實現run()方法 實現Callable介面,實現Call()方法 使用執行緒池,並向其提交任務task,其內部自動建立執行緒排程完成。 上述對比: 一般來說,使

Android執行(四)ThreadPoolExecutor類原始碼解析

使用ThreadPoolExecutor private final int CORE_POOL_SIZE = 4;//核心執行緒數 private final int MAX_POOL_SIZE = 5;//最大執行緒數 priv

Android 執行模擬多執行併發下載任務

廢話不多,直接上原始碼 自定義一個Adapter public class MyAdapter extends BaseAdapter { private Context context; private List<Progress> list

Android 執行的使用

執行緒池優點 提到執行緒池就必須先說一下執行緒池的優點,執行緒池的優點可以概括為以下四點: * 重用執行緒池中的執行緒,避免因為執行緒的建立和銷燬所帶來的效能開銷; * 執行緒池旨線上程的複用,就避免了建立執行緒和銷燬執行緒所帶來的時間消耗,減少執行

Android執行原始碼解析

     上一篇部落格大概瞭解了下執行緒池是什麼,這篇部落格將在原始碼的基礎上去驗證上一篇部落格中提到的 Thread執行流程。我的部落格保證是一個字一個字敲出來的    1.執行緒池原始碼解析     在ThreadPoolExecutor類中,最核心的任務提交方法是e

android 執行(原理及分析)

1.1 執行緒池的三大優點: 1)避免因為執行緒的建立和開銷所帶來的效能開銷, 2)能有效的控制執行緒池的最大併發數,避免大量執行緒間因為搶佔系統資源而導致的堵塞現象 3)能對執行緒進行簡單的管理,提供定時執行以及指定間隔迴圈執行功能 android中的執行緒池概念來源於

Android執行詳解

      最近在看OkHttp的原始碼,看著看著就看到了有執行緒池的地方,以前自己對這個東西就也就感到雲裡霧裡的,所以 想把執行緒池的知識點和原始碼完整的看一篇   1.執行緒池有什麼用?     

使用c語言實現執行以及執行原理

執行緒池介紹 執行緒池允許一個執行緒可以多次複用,且每次複用的執行緒內部的訊息處理可以不相同,將建立與銷燬的開銷省去而不必來一個請求開一個執行緒;簡單來說就是有一堆已經建立好的執行緒(最大數目一定),初始時他們都處於空閒狀態,當有新的任務進來,從執行緒池中取

淺談android執行

執行緒池的基本思想還是一種物件池的思想,開闢一塊記憶體空間,裡面存放了眾多(未死亡)的執行緒,池中執行緒執行排程由池管理器來處理。當有執行緒任務時,從池中取一個,執行完成後執行緒物件歸池,這樣可以避免反覆建立執行緒物件所帶來的效能開銷,節省了系統的資源。 比如:一個應用

java執行以及newCachedThreadPool使用過程中的問題

      為什麼要用執行緒池?原因很簡單,效能好,而且不用自己費心費力的管理執行緒       1、執行緒池基本說明及定義       從JDK 1.5開始,添加了Executors工具類,這個類定義了Executor、ExecutorService、ScheduledE

java&android執行-Executor框架之ThreadPoolExcutor&ScheduledThreadPoolExecutor淺析(多執行程式設計之三)

java多執行緒-概念&建立啟動&中斷&守護執行緒&優先順序&執行緒狀態(多執行緒程式設計之一)java多執行緒同步以及執行緒間通訊詳解&消費者生產者模式&死鎖&Thread.join()(多執行緒程式設計之二)

Android 執行

使用執行緒池可以給我們帶來很多好處,首先通過執行緒池中執行緒的重用,減少建立和銷燬執行緒的效能開銷。其次,能控制執行緒池中的併發數,否則會因為大量的執行緒爭奪CPU資源造成阻塞。最後,執行緒池能夠對執行緒進行管理,比如使用ScheduledThreadPool來設定延遲N秒後

執行Executors中的newSingleThreadExecutor和newFixedThreadPool(1)的區別

在上一篇【執行緒池】深入理解Executors類時,提到了newSingleThreadExecutor和newFixedThreadPool(1)的區別,查閱了大量資料,自己也做了一些實驗,但是還是有很多不清楚的地方,這篇文章主要是用作討論,如果有大佬有好的回答,拜託請多多

android執行

執行緒池的基本思想還是一種物件池的思想,開闢一塊記憶體空間,裡面存放了眾多(未死亡)的執行緒,池中執行緒執行排程由池管理器來處理。當有執行緒任務時,從池中取一個,執行完成後執行緒物件歸池,這樣可以避免反覆建立執行緒物件所帶來的效能開銷,節省了系統的資源。 比如:一個應用要和

Android.執行的原理和執行管理類的使用

執行緒池的原理 執行緒池使用來管理執行緒的,之所以稱為池,是因為其可以管理多條執行緒,所以需要用一個集合來管理執行緒,然後執行緒池是有大小的,當一個執行緒池管理的執行緒數目為計算機的cup數*2+1個

Android執行的使用及demo

一、為什麼要使用執行緒池:    1、減少了建立執行緒的數量,提高了APP的效能    2、節省開銷,防止併發執行緒過多,便於執行緒的管理 二、執行緒池的分類(四類) newCachedThreadPool 快取型執行緒池: 如果池中沒有執行緒可用,它將建

Java(Android)執行

介紹new Thread的弊端及Java四種執行緒池的使用,對Android同樣適用。本文是基礎篇,後面會分享下執行緒池一些高階功能。 1、new Thread的弊端 執行一個非同步任務你還只是如下new Thread嗎? Java 1234567newThre