前面分析了不少并发编程方面的东西,可是都是Java层面的,其实Google原生也提供了一些类方便咱们进行并发编程,比较常见的有HandlerThread,IntentService,AsyncTask,除此以外还有一些第三方框架Volley,Picasso等。java
研究这些类以及开源框架的实现,可让咱们更好地理解并发编程,甚至是本身也能够写一个异步框架也不是什么难事,下面就来从源码的角度按照顺序来先分析一下HandlerThread。编程
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called. 复制代码
一个好用的类用于建立一个自带Looper的线程。这个Looper能够用来建立Handler。注意start()方法必须首先被调用。bash
看过Handler的源码都应该比较熟悉,Handler的消息是须要Looper来进行轮询的,也就是每一个Handler建立的时候都须要传入一个Looper,不过咱们平时建立Handler的时候之因此不须要传入Looper,是由于主线程默认为咱们建立了一个looper,固然咱们也能够传入本身的Looper.因此为了不每次在子线程中建立Handler都须要建立Looper,Google为咱们提供了HandlerThread这个类。并发
int mPriority;//线程优先级
int mTid = -1;//线程ID
Looper mLooper;//建立线程的Looper
复制代码
继承关系比较简单,仅仅继承自Thread,在内部作了一些封装。框架
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
复制代码
这个方法Google都没有注释,太简单了,就是传入一个线程名称,而后优先级是默认的优先级0异步
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
复制代码
构造方法中新加了一个线程优先级ide
@Override
public void run() {
//获取进程ID
mTid = Process.myTid();
//Loopr准备
Looper.prepare();
//建立Looper
synchronized (this) {
mLooper = Looper.myLooper();
//唤醒全部等待的线程
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
//在Looper循环时作一些准备工做
onLooperPrepared();
//开启循环
Looper.loop();
mTid = -1;
}
复制代码
获取子线程的Looperoop
public Looper getLooper() {
//若是线程已经消亡,就返回null
if (!isAlive()) {
return null;
}
//若是线程已经建立了,就在此处停留等待Looper建立完成以后
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//等待线程被建立
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
复制代码
public boolean quit() //获取looper Looper looper = getLooper();
//退出looper
if (looper != null) {
looper.quit();
return true;
}
return false;
}
复制代码
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
复制代码
跟quit方法的惟一区别在于looper.quit()变成了looper.quitSafely(),如今具体分析一下这两个方法的区别post
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
复制代码
一个传入了false,一个传入了true,继续追踪ui
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
//移除消息队列中延迟的消息
removeAllFutureMessagesLocked();
} else {
//移除消息队列中全部的消息
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
复制代码
removeAllFutureMessagesLocked方法
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
//当消息队列中中的消息的发送时间大于当前时间
//就移除该消息
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
复制代码
因此看到这里,quit跟quidSafely的区别就在因而否移除消息队列中还未发送也就是延迟的消息。
//建立mHandlerThread
mHandlerThread = new HandlerThread("main");
//获取HandlerThead中的Looper
Looper looper = mHandlerThread.getLooper();
//建立子线程中的Looper
Handler handler = new Handler(looper);
//执行耗时操做
handler.post(new Runnable() {
@Override
public void run() {
//子线程中执行耗时操做
}
});
//界面销毁的时候须要销毁Looper
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
复制代码
若是没有HandlerThread,咱们须要手动去建立一个线程,如今HandlerThread能够帮咱们简化这个操做,可是有一点须要注意的是,因为咱们的异步操做是存放在Handler的消息队列中的,因此是串行的,因此只适合并发量较少的耗时操做。