一、ThreadLocal的分析:
從字面上這個Threadlocal很容易讓人引起誤解,認真是一個本地 thread,實際上這是一個Thread的本地資訊變數,也就是說用來儲存線程中不安全變數的一個機制。分析如下:
ThreadLocal類介面很簡單,只有4個方法,我們先來瞭解一下:
void set(Object value)
設定當前線程的線程局部變數的值。
· public Object get()
該方法返回當前線程所對應的線程局部變數。
· public void remove()
將當前線程局部變數的值刪除,目的是為了減少記憶體的佔用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變數將自動被記憶體回收,所以顯式調用該方法清除線程的局部變數並不是必須的操作,但它可以加快記憶體回收的速度。
protected Object initialValue()
返回該線程局部變數的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,線上程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的預設實現直接返回一個null。
對於每個線程,同名的變數,我們可以建立一個執行個體,並以Thread.currentThread為key儲存到ThreadLocal中。當我們用到的時候,通過get()擷取。
對於Handler,通常存的是 mLooper
二、Handler究竟是運行在子線程還是主線程
來看看Handler的建構函式,這裡面有一個變數進行如下操作:
mLooper = Looper.myLooper();
上面的調用實際是如下操作:
public static Looper myLooper() {
return sThreadLocal.get();
}
也就是擷取當前線程的Looper,這樣看來,Handler運行環境不是確定的,而是在哪個線程建立這個handler,在主線程建立就運行在主線程,否則就是子線程。
三、如何正確啟動一個子線程:
//在主線程先建立一個HandlerThread
HandlerThread mHandlerThread = new HandlerThread("XXX");
//第二步,是建立一個自己的Looper
mHandlerThread.start();
建立一個繼承自Handler的子類,將上面建立的Looper賦給這個子類,在建立的時候,這樣,我們就是建立一個不是運行在主線程的子線程了。否則,預設的是使用啟動Handler的線程的Looper。
class myThread extends Handler {
public myThread (Looper looper) {
super(looper);
}
public myThread() {
super();
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
try {
Thread.sleep(20* 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
//初始化
mHandlerThread = new HandlerThread("handler");
mHandlerThread.start();
//建立子線程
mHandler = new myThread(mHandlerThread.getLooper());
四、IntentService
IntentService繼承自Service,它能夠在後台運行不阻塞主線程主要歸於它內部開啟一個背景工作執行緒,也就是建立一個繼承自Handler的ServiceHandler,只是這個handler的looper是新建立的,不同於主線程的Looper,因而不會阻塞主線程。
public abstract class IntentService extends Service {
}
當我們通過Intent啟動一個IntentService的時候,先進入onCreate:
public void onCreate() {
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
是不是通過HandlerThread先建立一個Looper,然後將這個Looper賦給背景工作執行緒ServiceHandler
啟動好IntentService之後,我們開始
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
ServiceHandler的函數中有處理訊息的機制,這裡就調用onHandleIntent進行處理
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
五、如何銷毀線程
1、銷毀Handler:
由上面我們知道:我們開啟一個子線程重要的依據在於要建立一個HandlerThread,在這裡會建立一個Looper,然後通過它進行處理Message。那麼在退出時如下處理:
onDestroy() {
super.onDestroy();
//將HandlerThread的looper.quit,下面應該是執行個體調用quit(此處不考慮文法問題)
HandlerThread.quit();
}
對於以Handler.post(Runnable)形式發送Message的方式,在上面函數中應該是:
Handler.removeCallbacks(mRunnable);
2、銷毀Thread
目前是通過:設定一個全域變數,在退出時將這個變數設定為true,thread中判斷到這個值為true時退出thread的迴圈。
作者:kakaBack