Android中線程和線程池


我們知道線程是CPU調度的最小單位。在Android中主線程是不能夠做耗時操作的,子線程是不能夠更新UI的。在Android中,除了Thread外,扮演線程的角色有很多,如AsyncTask,IntentService和HandlerThread等等。由於內容過多,所以將分為上下兩部分,第一部分主要和大家談談Android中的線程,以及在Android中的常用的線程池。第二部分我們一起來了解一下AsyncTask的使用和工作原理。

 

1、HandlerThread

HandlerThread是Thread的子類,它是一種可以使用Handler的Thread,它的實現比較簡單。我們來看看它的源碼:

 1 package android.os;
 2 
 3 public class HandlerThread extends Thread {
 4     int mPriority;
 5     int mTid = -1;
 6     Looper mLooper;
 7 
 8     public HandlerThread(String name) {
 9         super(name);
10         mPriority = Process.THREAD_PRIORITY_DEFAULT;
11     }
12     
13 
14       public HandlerThread(String name, int priority) {
15         super(name);
16         mPriority = priority;
17     }
18     
19 
20        protected void onLooperPrepared() {
21     }
22 
23 
24 
25     @Override
26     public void run() {
27         mTid = Process.myTid();
28         Looper.prepare();
29         synchronized (this) {
30             mLooper = Looper.myLooper();
31             notifyAll();
32         }
33         Process.setThreadPriority(mPriority);
34         onLooperPrepared();
35         Looper.loop();
36         mTid = -1;
37     }
38     
39 
40 
41      public Looper getLooper() {
42         if (!isAlive()) {
43             return null;
44         }
45         
46         // If the thread has been started, wait until the looper has been created.
47         synchronized (this) {
48             while (isAlive() && mLooper == null) {
49                 try {
50                     wait();
51                 } catch (InterruptedException e) {
52                 }
53             }
54         }
55         return mLooper;
56     }
57 
58 
59 
60        public boolean quit() {
61         Looper looper = getLooper();
62         if (looper != null) {
63             looper.quit();
64             return true;
65         }
66         return false;
67     }
68 
69 
70 
71 
72 
73       public boolean quitSafely() {
74         Looper looper = getLooper();
75         if (looper != null) {
76             looper.quitSafely();
77             return true;
78         }
79         return false;
80     }
81 
82 
83 
84 
85      public int getThreadId() {
86         return mTid;
87     }
88 }

為了讓大家看清楚,我們源碼的一些英文注釋干掉了,現在就很清晰了。整個類中,除了構造方法和對外提供幾個public方法以外,就剩一個方法了run()。從它的實現來看,和普通的Thread實現沒有什么區別。都是在run()方法中執行耗時操作。不過,HandlerThread內部創建了消息隊列,並且run()方法是一個無限循環的方法,當我們不需要HandlerThread的時候,我們可以調用quitSafely()或者quit()方法來結束這個線程。這是比較方便的。

 

 

2、IntentService

IntentService是一種特殊的Service,它是Service的子類,並且它是一個抽象類,所以必須創建它的子類才可以使用Intent Service。Intent Service可用於執行后台的耗時任務,當任務執行完畢,它會自己結束,不需要開發着手動結束它。這里需要注意一個問題,Intentservice內置有線程,但是它還是屬於Service,所以它的優先級會比線程高很多,所以不容易被系統殺死。所以比較合適去執行一些優先級比較高的任務。看看它的源碼:

  1 package android.app;
  2 
  3 import android.annotation.WorkerThread;
  4 import android.annotation.Nullable;
  5 import android.content.Intent;
  6 import android.os.Handler;
  7 import android.os.HandlerThread;
  8 import android.os.IBinder;
  9 import android.os.Looper;
 10 import android.os.Message;
 11 
 12 
 13 
 14 public abstract class IntentService extends Service {
 15     private volatile Looper mServiceLooper;
 16     private volatile ServiceHandler mServiceHandler;
 17     private String mName;
 18     private boolean mRedelivery;
 19 
 20 
 21 
 22     private final class ServiceHandler extends Handler {
 23         public ServiceHandler(Looper looper) {
 24             super(looper);
 25         }
 26 
 27 
 28 
 29         @Override
 30         public void handleMessage(Message msg) {
 31             onHandleIntent((Intent)msg.obj);
 32             stopSelf(msg.arg1);
 33         }
 34     }
 35 
 36 
 37 
 38 
 39     public IntentService(String name) {
 40         super();
 41         mName = name;
 42     }
 43 
 44 
 45 
 46 
 47    public void setIntentRedelivery(boolean enabled) {
 48         mRedelivery = enabled;
 49     }
 50 
 51     @Override
 52     public void onCreate() {
 53         // TODO: It would be nice to have an option to hold a partial wakelock
 54         // during processing, and to have a static startService(Context, Intent)
 55         // method that would launch the service & hand off a wakelock.
 56 
 57         super.onCreate();
 58         HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
 59         thread.start();
 60 
 61         mServiceLooper = thread.getLooper();
 62         mServiceHandler = new ServiceHandler(mServiceLooper);
 63     }
 64 
 65 
 66 
 67 
 68     @Override
 69     public void onStart(@Nullable Intent intent, int startId) {
 70         Message msg = mServiceHandler.obtainMessage();
 71         msg.arg1 = startId;
 72         msg.obj = intent;
 73         mServiceHandler.sendMessage(msg);
 74     }
 75 
 76 
 77 
 78 
 79       @Override
 80     public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
 81         onStart(intent, startId);
 82         return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
 83     }
 84 
 85 
 86 
 87 
 88     @Override
 89     public void onDestroy() {
 90         mServiceLooper.quit();
 91     }
 92 
 93 
 94 
 95 
 96     public IBinder onBind(Intent intent) {
 97         return null;
 98     }
 99 
100 
101 
102 
103     @WorkerThread
104     protected abstract void onHandleIntent(@Nullable Intent intent);
105 }

這里就很簡單了,這些方法對於經常使用Service的朋友來說,就很熟悉了。大家看onCreate()方法。沒錯IntentService就是封裝了HandlerThread和Handler。

當我們啟動IntentService是onCreate(),方法將會被調用,然后就會創建HandlerThread和ServiceHandler。而onStartCommand()方法又調用了onStart()方法,從onStart()方法可以看出IntentService 僅僅是通過ServiceHandler來發一個消息,這個消息會在HandlerThread中被處理掉。

大家看這個onStart()方法,將intent作為消息傳遞給onHandleIntent,這個intent通常是我們傳遞進來的數據。而onHandleIntent就是通過這個intent來區別具體的后台任務的。 

 

好了,AsyncTask的使用和工作原理。我們會在下一章在說。下面我們看看線程池吧。

不知道大家有沒有遇到過這種情況。我們在寫項目,遇到耗時操作的時候,怎么辦呢,是不是new Thread().start,那這樣的話,整個項目中得new多少個Thread。這種明顯是很浪費性能。畢竟線程也是好資源的嘛。那么有沒有一種可以方法對線程進行復用呢?答案就是線程池。

 

先說一下線程池的好處:

1、重用線程池中的線程,避免因為線程的創建和銷毀帶來的性能開銷。

2、能有效的控制線程池中的線程並發數,避免大量線程之間因為互相搶占資源而導致的阻塞現象。

3、能夠對線程進行簡單的管理,並提供定時執行以及指定間隔循環執行等功能。

 

ThreadPoolExecutor

Android中的線程池概念是來源於java中Executor,Executor是一個空的接口,真正的線程池實現ThreadPoolExecutor。

1 public ThreadPoolExecutor(int corePoolSize,
2                               int maximumPoolSize,
3                               long keepAliveTime,
4                               TimeUnit unit,
5                               BlockingQueue<Runnable> workQueue,
6                               ThreadFactory threadFactory) {
7         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
8              threadFactory, defaultHandler);
9     }

簡單介紹一下ThreadPoolExcutor各個參數的含義

corePoolSize:線程池的核心線程數,默認情況下,核心線程會在線程池中一直存活,即使他們處於閑置狀態。當我們把ThreadPoolExecutor中的allowCoreThreadTimeOut屬性設置為true,那么閑置的核心線程在等待新任務的時候,如果時間超過keepAliveTime所設置的時間,核心線程將會被回收。

maximumPoolSize:設置最大線程池能夠容納的最大線程數,當線程池中的線程達到這個數以后,新任務將會被阻塞。

 

keepAliveTime:非核心線程數閑置的時間。

unit:指定keepAliveTime參數的時間單位。

workQueue:線程池中的任務隊列。

threadFactory:線程工廠,為線程池提供創建新線程的功能。

 

 

線程池的分類

Android中常見的線程池有四種,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。

 

FixedThreadPool

FixedThreadPool線程池是通過Executors的new FixedThreadPool方法來創建。它的特點是該線程池中的線程數量是固定的。即使線程處於閑置的狀態,它們也不會被回收,除非線程池被關閉。當所有的線程都處於活躍狀態的時候,新任務就處於隊列中等待線程來處理。注意,FixedThreadPool只有核心線程,沒有非核心線程。

1 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
2         return new ThreadPoolExecutor(nThreads, nThreads,
3                                       0L, TimeUnit.MILLISECONDS,
4                                       new LinkedBlockingQueue<Runnable>(),
5                                       threadFactory);
6     }

 

 

CachedThreadPool

CachedThreadPool線程池是通過Executors的newCachedThreadPool進行創建的。它是一種線程數目不固定的線程池,它沒有核心線程,只有非核心線程,當線程池中的線程都處於活躍狀態,就會創建新的線程來處理新的任務。否則就會利用閑置的線程來處理新的任務。線程池中的線程都有超時機制,這個超時機制時長是60s,超過這個時間,閑置的線程就會被回收。這種線程池適合處理大量並且耗時較少的任務。這里得說一下,CachedThreadPool的任務隊列,基本都是空的。

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

 

ScheduledThreadPool

ScheduledThreadPool線程池是通過Executors的newScheduledThreadPool進行創建的,它的核心線程是固定的,但是非核心線程數是不固定的,並且當非核心線程一處於空閑狀態,就立即被回收。這種線程適合執行定時任務和具有固定周期的重復任務。

 1 public static ScheduledExecutorService newScheduledThreadPool(
 2             int corePoolSize, ThreadFactory threadFactory) {
 3         return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
 4     }
 5 
 6 
 7 public ScheduledThreadPoolExecutor(int corePoolSize,
 8                                        ThreadFactory threadFactory) {
 9         super(corePoolSize, Integer.MAX_VALUE,
10               DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
11               new DelayedWorkQueue(), threadFactory);
12     }

 

SingleThreadExecutor

SingleThreadExecutor線程池是通過Executors的newSingleThreadExecutor方法來創建的,這類線程池中只有一個核心線程,也沒有非核心線程,這就確保了所有任務能夠在同一個線程並且按照順序來執行,這樣就不需要考慮線程同步的問題。

 

 1 public static ExecutorService newSingleThreadExecutor() {
 2 
 3         return new FinalizableDelegatedExecutorService
 4 
 5             (new ThreadPoolExecutor(1, 1,
 6 
 7                                     0L, TimeUnit.MILLISECONDS,
 8 
 9                                     new LinkedBlockingQueue<Runnable>()));
10 
11     }

 

好了,寫了這么多,真特么累,下部分就和大家分享一下AsyncTask的 工作原理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM