allbet gaming电脑版下载:看完这篇。再也不怕被问 HandlerThread 的原理

admin/2020-07-28/ 分类:科技/阅读:

HandlerThread是什么

官网先容

A Thread that has a Looper. The Looper can then be used to create Handlers. Note that just like with a regular Thread, Thread.start() must still be called. 

翻译:

HandlerThread,持有一个可用来构建Handlers的Looper,像一个通例的线程类,必须要挪用start()才气正常事情。

HandlerThread的父类是Thread,以是HandlerThread的本质照样一个线程,然则它并非像Thread需要在run代码块内执行耗时的义务,HandlerThread是通过搭配外部的Handler分发处置新闻执行义务的,可以很简朴地返回和治理子线程的一个Looper工具。

HandlerThread常见的使用场景

有两个耗时义务A、B,义务B的执行需要A执行效果,即 A,B不可以并行执行,而是要串行按顺序执行义务。

下面给出模拟这种场景HandlerThread使用的实例代码:(代码可直接复制运行,有点长有点渣,见谅)

getResultA()doThingB(),模拟了A,B两个不可以并行执行的耗时义务。

taskHandlerHandler子类的实例,通过获取handlerThread开启后建立的Looper,串行发送了新闻A,新闻B,Looper自然也是先取出新闻A,给taskHandler.handleMessage处置,再取出新闻B完成了串行执行耗时义务A、B。

完成了串行执行耗时义务A、B。

public class HandlerThreadActivity extends AppCompatActivity { private Handler taskHandler; private HandlerThread handlerThread; private static String resultA; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handlerThread = new HandlerThread("HandlerThread-1"); //!!要害:HandlerThread需要挪用start开启线程,否则持有Looper为null handlerThread.start(); //使用handlerThread线程持有的Looper构建 taskHandler实例 taskHandler = new TaskHandler(handlerThread.getLooper()); //发送新闻A Message msgA = Message.obtain(); msgA.what = 0; msgA.obj = "Task-A"; taskHandler.sendMessage(msgA); //发送新闻B Message msgB = Message.obtain(); msgB.what = 1; msgB.obj = "Task-B"; taskHandler.sendMessage(msgB); } @Override protected void onDestroy() { super.onDestroy(); //手动退出HandlerThread的Looper handlerThread.quitSafely(); } @WorkerThread private static String getResultA() { try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } return "DMingO"; } @WorkerThread private static void doThingB() { try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() " :" resultA " 's blog"); } private static class TaskHandler extends Handler{ public TaskHandler(@NonNull Looper looper) { super(looper); } @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: //执行耗时义务 getResultA() resultA = getResultA(); break; case 1: if(! "".equals(resultA)){ //拿到义务A的返回效果才气执行义务B doThingB(); } break; default: break; } } } } 

运行效果:

可以看到TaskHandler.handleMessage是运行在HandlerThread这一个线程上,归根结底照样HandlerThread把它线程的Looper给了TaskHandler实例

I/System.out: HandlerThread-1 :DMingO 's blog 

HandlerThread起的最大作用就是 很简捷地提供了一个可设置命名和优先级的线程的Looper工具

HandlerThread源码剖析

通过最简朴的使用入手剖析HandlerThread作为一个线程,提供一个子线程的Looper的背后原理:

 handlerThread = new HandlerThread("HandlerThread-1"); handlerThread.start(); taskHandler = new TaskHandler(handlerThread.getLooper()); 

看下getLooper()葫芦里什么药:

 public Looper getLooper() { //isAlive()判断当前线程是否已经开启 //若是线程未开启(未挪用HandlerThread.start),会返回null //以是必须执行了start()后,才气挪用 getLooper(),否则会有空指针异常 if (!isAlive()) { return null; } // 若是线程已开启但Looper未被建立,会进入同步代码块,壅闭-->直到Looper被建立 synchronized (this) { while (isAlive() && mLooper == null) { try { //mLooper==null-->线程进入壅闭状态 wait(); } catch (InterruptedException e) { } } } //确保 返回的mLooper不为null return mLooper; } 

通过剖析,getLooper() 方式确保可以返回一个HandlerThread线程持有的且非空的Looper工具。条件是HandlerThread线程已经开启。若是线程已开启但Looper未被建立,线程会壅闭,直到Looper被建立了。

那么在哪个方式,mLooper才被赋值,Looper工具才被建立呢?还记得 getLooper() 方式在最初若是发现线程未被开启,直接就返回null,这不就说明HandlerThread线程的开启与否与它的Looper建立,这两者息息相关嘛。

那就再看下HandlerThread的run()方式有什么名堂:

 @Override public void run() { mTid = Process.myTid(); //建立此线程的Looper和MessageQueue Looper.prepare(); synchronized (this) { //给 mLooper 赋值 mLooper = Looper.myLooper(); //此时mLooper!=null-->作废线程壅闭 notifyAll(); } //为线程设置mPriority优先级 Process.setThreadPriority(mPriority); onLooperPrepared(); //最先运行 Looper Looper.loop(); mTid = -1; } 

开启HandlerThread线程后,会建立此线程的Looper和MessageQueue,设置线程优先级,最先Looper的循环取新闻。

欸,HandlerThread这名字,它的Handler又去哪儿了呢?emmmm现在被隐藏了:

 private @Nullable Handler mHandler; /** * 返回与此线程相关联的一个Handler实例 * @hide 现在此方式是被隐藏的,无法正常直接挪用 */ @NonNull public Handler getThreadHandler() { if (mHandler == null) { mHandler = new Handler(getLooper()); } return mHandler; } 

可以看出,HandlerThreadmHandler的实例化是属于懒加载方式,只能在外界挪用 getThreadHandler()的时刻,才会对mHandler判空&举行实例化。实例化时传入的Looper工具自然是HandlerThread这一线程建立的Looper。因此若Looper还未被初始化,方式也会一直壅闭直到Looper建立完成,也需要线程已开启。

毫无疑问,mHandler 也自然也是只能去处置HandlerThread这一个线程的新闻。

可以看出HandlerThread这个类与Looper的关系是密不可分的,自然也会有退出Looper的设施,看以下两个方式:

 public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } 

是不是以为高度相似,而这两个方式相同的地方是:

  • 若是线程未开启时(looper自然也为null),返回 false
  • 若是线程已经开启了,则会挪用 Looper类的quit() / quitSafely()方式,并返回 true

差别的是,凭据官方形貌,建议使用quitSafely(),这会允许新闻行列中还在排队的新闻都被取出后再关闭,制止所有挂起的义务无法有序的被完成。

HandlerThread剖析总结

HandlerThread 本质是一个Thread,却和通俗的 Thread很差别的是:通俗的 Thread 主要被用在 run 方式中执行耗时义务,而 HandlerThread 在线程开启后(run方式中)建立了该线程的Looper和新闻行列,外界Handler可以很利便获取到这个Looper,搭配执行耗时义务,适合串行执行耗时义务等场景。

,

联博统计

www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。

TAG:
阅读:
广告 330*360
广告 330*360

热门文章

HOT NEWS
  • 周榜
  • 月榜
Sunbet_进入申博sunbet官网
微信二维码扫一扫
关注微信公众号
新闻自媒体 Copyright © 2002-2019 Sunbet 版权所有
二维码
意见反馈 二维码