Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> java/android線程池詳解

java/android線程池詳解

編輯:Android編程入門

一,簡述線程池:

線程池是如何工作的:一系列任務出現後,根據自己的線程池安排任務進行。

如圖:

 

線程池的好處:

  1. 重用線程池中的線程,避免因為線程的創建和銷毀所帶來的性能開銷。
  2. 能有效控制線程池的最大並發數,避免大量的線程之間因互相搶占系統資源而導致的阻塞現象。
  3. 能對線程進行簡單的管理。並提供定時執行以及指定間隔循環執行等功能。

 

線程池的具體實現為ThreadPoolExeutor,其接口為Executor

ThreadPoolExecutor提供了一系列的參數用於配置線程池。

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

參數含義如下:

  1. corePoolSize :線程池核心線程數,默認情況下,核心線程會在線程池中一直存活,即使他們處於閒置狀態。其有一個allowCoreThreadTimeOut屬性如果設置為true,那麼核心線程池會有超時策略。超時的時長為第三個參數  keepAliveTime 。如果超時,核心線程會被終結。
  2. maxmumPoolSize: 線程池所能容忍的最大線程數,當活動線程數達到這個數值後,後續的新任務會被阻塞。
  3. keepAliveTime:非核心線程閒置時的超時時長,超過這個時長就會被非核心線程會被回收。這個參數如同第一個參數,如果設置相關屬性後也會作用於核心線程。、
  4. unit:指定keepAliveTime的參數時間單位。這是一個枚舉,常用的有MILLISECONDS(毫秒)、SECONDS(秒)等
  5. workQueue:線程池的任務隊列,通過execute()方法(執行方法)提交的Runable對象會存儲在這個參數中。
  6. threadFactory:線程工廠,為線程池提供創建新線程的功能。

其執行任務時大致遵顼如下規則:

  1. 如果線程達到核心線程數量,那麼回直接啟動一個核心線程。
  2. 線程未達到核心線程的數量,任務會被插入到任務隊列(workQueue)排隊。
  3. 如果任務隊列已滿導致步驟二無法插入到任務隊列,那麼開啟一個非核心線程執行。
  4. 如果步驟三的線程數量達到線程池規定數目(maxmumPoolSize),那麼拒絕執行此任務。

二,線程池的相關類結構解析

看一下線程池的類結構圖:

  

  說以下這幾點:

     這是一個抽象工廠模式!

  Executor和Executors的區別:

  Executor僅僅是一個接口,其只有一個方法,execute()方法(執行方法)。

public interface Executor {


    void execute(Runnable command);
}

   而Executors是一個沒有繼承任何類的方法,其作為一個工廠方法類,用於創建形形色色的線程池等對象。如:FixedThreadPool、defaultThreadFactory(下面會具體講),而這些具體的線程池方案(FixedThreadPool)亦或者自定義的線程池方案(ThreadPoolExeutor)都是來自ExecutorService接口,這個接口也是繼承於Executor接口。通過類結構圖可以很清楚的看到。

如,Executors生產出ExecutorService對象,源碼如下

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

 

 說到工廠模式,ThreadPoolExeutor的參數threadFactory是一個接口,僅有newThread方法,代碼如下

  

public interface ThreadFactory {

    Thread newThread(Runnable r);
}

 

其作用和executor接口類似,體現面向接口編程思想。其中例如如下兩個方法,是工廠方法類Executors所生成的ThreadFactory對象。

 public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }

       public static ThreadFactory privilegedThreadFactory() {
        return new PrivilegedThreadFactory();
    }
 

 defaultThreadFactory是這樣創建線程的,如果要自定義不妨參照一下。

  

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

 

三 具體線程池的使用


說了那麼多,要具體看看系統提供的線程池,主要是這四個:

  1. FixedTreadPool. fixed有穩固的含義,通過工廠方法類Executors的newFixedThreadPool方法創建。它是線程數量固定的線程池,僅有核心線程且沒有超時策略,所以線程不會被回收。這意味著它能夠快速的響應外界請求。

  例子:這裡設置了4個runnable和2個核心線程。

  Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Log.d("hello","sleep前");
                SystemClock.sleep(3000);
                Log.d("hello", "sleep後");
            }
        };
......

   ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(runnable);
        executorService.execute(runable1);
        executorService.execute(runable2);
        executorService.execute(runable3);

輸出如下,

06-24 15:49:47.962 12462-12497/? D/hello: sleep1前
06-24 15:49:47.962 12462-12496/? D/hello: sleep前
06-24 15:49:50.962 12462-12497/com.example.hang.myapplication D/hello: sleep1後
06-24 15:49:50.962 12462-12497/com.example.hang.myapplication D/hello: sleep2前
06-24 15:49:50.972 12462-12496/com.example.hang.myapplication D/hello: sleep後
06-24 15:49:50.972 12462-12496/com.example.hang.myapplication D/hello: sleep3前
06-24 15:49:53.962 12462-12497/com.example.hang.myapplication D/hello: sleep2後
06-24 15:49:53.972 12462-12496/com.example.hang.myapplication D/hello: sleep3後

可以看到,每次僅有兩個線程去執行,當其中一個執行完畢後才輪到下一個。
當 核心線程數量改為 4 時,則會一次性執行完這4個runnable。

  1. CachedThreadPool.它是一種線程數量不定的線程池,只有非核心線程,可以簡單理解為最大線程數是無限大的。CachedThreadPool的任務隊列相當於一個空集合,這導致任何任務都會被立即執行,比較適合做一些大量的耗時較少的任務。

 例子,修改為將上述的  ExecutorService executorService = Executors.newFixedThreadPool(2);替換為

ExecutorService executorService = Executors.newCachedThreadPool();,輸出如下,一次性執行4個線程,且線程順序不定。
06-24 15:53:08.582 16801-16873/com.example.hang.myapplication D/hello: sleep2前
06-24 15:53:08.582 16801-16872/com.example.hang.myapplication D/hello: sleep1前
06-24 15:53:08.582 16801-16871/com.example.hang.myapplication D/hello: sleep前
06-24 15:53:08.582 16801-16875/com.example.hang.myapplication D/hello: sleep3前
06-24 15:53:11.582 16801-16873/com.example.hang.myapplication D/hello: sleep2後
06-24 15:53:11.582 16801-16872/com.example.hang.myapplication D/hello: sleep1後
06-24 15:53:11.582 16801-16871/com.example.hang.myapplication D/hello: sleep後
06-24 15:53:11.582 16801-16875/com.example.hang.myapplication D/hello: sleep3後

 

  1. ScheduledThreadPool.Scheduled有 “預定的” 意思。核心線程池的數量書固定的且非核心線程池是沒有限制的,非核心線程池被閒置時會被立即回收。主要用於執行定時任務和具有固定周期的重復任務。

  例子:這裡是延遲2000ms後開始執行

 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService.schedule(runnable,2000, TimeUnit.MILLISECONDS);
        scheduledExecutorService.schedule(runable1, 2000, TimeUnit.MILLISECONDS);
        scheduledExecutorService.schedule(runable2, 2000, TimeUnit.MILLISECONDS);
        scheduledExecutorService.schedule(runable3, 2000, TimeUnit.MILLISECONDS);

  例子:延遲10ms後開始每1000ms執行一次runnable。

 scheduledExecutorService.scheduleAtFixedRate(runnable,10,1000,TimeUnit.MILLISECONDS);

 

  1. SingleThreadExecutor.只有一個核心線程,所以確保所有的任務都是在一個線程裡順序執行。把所有的任務都放到一個線程,這樣有一個好處是不需要處理線程同步問題。

 這裡就不做例子了,就是4個排著隊依次執行,且不會亂序。

  

06-24 16:05:02.782 32057-32125/com.example.hang.myapplication D/hello: sleep前
06-24 16:05:05.782 32057-32125/com.example.hang.myapplication D/hello: sleep後
06-24 16:05:05.782 32057-32125/com.example.hang.myapplication D/hello: sleep1前
06-24 16:05:08.782 32057-32125/com.example.hang.myapplication D/hello: sleep1後
06-24 16:05:08.782 32057-32125/com.example.hang.myapplication D/hello: sleep2前
06-24 16:05:11.782 32057-32125/com.example.hang.myapplication D/hello: sleep2後
06-24 16:05:11.782 32057-32125/com.example.hang.myapplication D/hello: sleep3前
06-24 16:05:14.782 32057-32125/com.example.hang.myapplication D/hello: sleep3後
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved