前面分析了很多并发编程方面的东西,但是都是 Java 层面的,其实 Google 原生也提供了一些类方便我们进行并发编程,比较常见的有 HandlerThread,IntentService,AsyncTask,除此之外还有一些第三方框架 Volley,Picasso 等。
研究这些类以及开源框架的实现,可以让我们更好地理解并发编程,甚至是自己也可以写一个异步框架也不是什么难事,下面就来从源码的角度按照顺序来先分析一下 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() 方法必须首先被调用。
看过 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;
- }
构造方法中新加了一个线程优先级
- @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;
- }
获取子线程的 Looper
- 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(),现在具体分析一下这两个方法的区别
- public void quit() {
- mQueue.quit(false);
- }
- public void quitSafely() {
- mQueue.quit(true);
- }
一个传入了 false,一个传入了 true,继续追踪
- 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 的消息队列中的,所以是串行的,所以只适合并发量较少的耗时操作。
来源: https://juejin.im/post/5a48acfd6fb9a0451969ee5a