HandlerThread源码剖析

1 怎样用?

现在假定有个场景,需求你在子线程里边跑个耗时操作,怎样搞?
不BB,上代码,首要定义一个子线程,里边需求有个Handler:

public class MThread extends Thread {线程
//需求有个Handl线程的几种状况er
private Handler handler;
@Override
public void run() {
Looper.prepare(); //创立Looper
handler = new Handler(); //创立Handler,这时候Handler会取其时线程的Looper
Looper.loop(); //轮询
}
//对外供给线程的几种状况自己的Handler
public Handler getHandler() {
return handler;
}
}

创立好了子线程后,咱们开端运用

MThread mThread = new MThread(); //创立线程
mThread.start(); //让线程跑起来
mThread.getHandler().sendMessage(new Message()); //获取这个线程的Handler,并发音讯

这个时指针式万用表候咱们发现大概率会抛出空指针反常,提示m指针万用表的使用方法Thread.getHandler()是个null,为什么呢,由于咱们在mThread.start()之后,立刻去获取它的Handler,此时或许MThread.run()还没跑完,或者说里边的那句
handler = new Handler()还没实行到安全教育渠道登录,并且这样运用也太麻烦了,so,HandlerThread出场了,咱们直接看它线程的几种状况的源码:

2 源码剖析

public class HandlerThread e指针c言语xtends Thre指针数学ad {
int mPriority;
i指针式万用表nt mTi指针表d = -1;
Looper mLooper; //供给一个其时线程的概念线程的安全出产月Looper
private @Nullable Handler mHandler; //供给一个Handler
public HandlerThread(String name) {
super(name);
mPri指针式万用表ority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priori安全教育渠道ty) {
supe源码怎么做成app软件r(name);
mPriority = priorit安全期是哪几天y;
}
//这个是在Looper创立好后回调的,可以在这儿边直接获取Looper
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); //安全这儿创立了L指针万用表的读法ooper
synchronized (this) { //这儿加锁了
mLoop源码之家er = Looper.myLooper();线程池面试 //给mLooper赋值
notifyAll(); //唤醒其他等候"this"锁的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared(); //回调
Looper.loop(); //轮询安全出产法
mTid = -1;
}
//获取Looper
public Looper getLooper() {
if (!源码年代训练怎么样isAlive()) { //假定当线程是什么意思时线程现已不存在了,就回来null,变相避免了死锁
return源码怎么做成app软件 null;
}
s线程安全ynchro源码年代训练怎么样nized (this) { //加锁,跟创立Looper那里相照顾
while (isAlive() &&线程池面试题 mLooper == null指针万用表的读法) { //假定线程还存活并且mLooper为空,也就是说run()里边还没跑完
try {
wait(线程是什么意思); //就等着,等候run()里边的那个notifyAll()
} catch (Interrup源码编辑器编程猫tedException e) {
}
}
}
return mLooper; //回来
}
//获取Handler
public Hand源码编辑器编程猫ler getThreadHandler() {
if (mHandler == null) {
m线程Handler = new Handler(getLoope源码r(线程和进程的区别是什么))指针c言语;  //这儿也调用了getLooper(),所以假定mLooper还源码年代没创立完,也会卡在这儿
}
return mHandler;
}
//退出,会删去Mess指针变量ageQueue里边的悉数音讯
public boolean quit() {
Looper looper = getLooper();
if (looper != n指针万用表的使用方法ull) {
looper.quit();
return tru指针数学e;
}
return fals安全工程e;
}指针
//安全退出,只会删去MessageQueue里边的将来才实行的音讯,比方在时刻A调用了quitSafely,那么MessageQueue里边实行时刻msg.when>=A的才会被收回,其他保存
public boolean quitSafely()指针式万用表 {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}

通过上面代码咱们知道了:

  • 1 HandlerThread是个Thread,里边有个Handler和Looper
  • 2 在run()里边去创立Looper,加了同指针式万用表图片步锁,锁对象是自己
  • 3 供给一个getLooper()函数来获取其时线程的Looper,加安全教育渠道登录了同步锁,锁对象是自己
  • 4 在getHa指针万用表的读法nd线程池创立的四种ler()里边去getLooper()来创立Handler
  • 5 所以假定Looper还没被赋值,指针式万用表图片那么其时线程会wait(),直到MThread的run里边的synchronized块跑完,才会回来并继续实行

问:假定先getLooper()在mThread.start()呢,会死锁吗?比方:

MThread thread = new MThread();
t源码资本hread.getLoope线程的几种状况r(); //这个调完后,他会synchronized(this)持有this锁,并线程池创立的四种且卡在wait()那里等候notify
thre线程撕裂者ad.start(); //这个调完了,它的run()里边的synchronized(this)进不去,卡在那里等候this锁,这样跟上面就形成了死锁

答: 不会,由于thread.getLooper()的时候,假定线程安全还没start(),那么isAlive()就是fals指针万用表的使用方法e,他就会立刻回来null,所以不会。

问: 可是线程具有不确定性,假定我先st源码编辑器art()线程,然后等到它的跑到run()里边的synchronized(th指针式万用表图片is),然后立刻去th线程是什么意思read.getLooper(),此时就跳过了if(isAlive())检测
可是此时假定getLooper()里边的synchr安全出产法onized()先获取到了this呢?流程如下:

public void run() {
mTid = Process.myTid();
L线程撕裂者ooper.pre指针表pare();源码之家 // (1先跑安全教育到了这儿)
synchronized (this) { //(4那么这儿跑不到,等着,卡住了)
mLooper = Looper.myLooper(); //给mLooper赋值
notifyAll(); //唤醒其他等候"this"锁的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared(); //回调
Loo源码交易网站源码per.loop(); //轮询
mTid = -1;
}
//获取Looper
p源码交易网站源码ublic Looper getLooper() {
if (!isAlive()) { //(2跑到了这儿)
return null;
}
synchronized (this) { //(3 又跑到了这儿,先获取到this锁)
while (isAlive() && mLooper == null) { //(5跑线程的概念到这了,俩条件契合,等)
try {
wait(); (6)
} catch (InterruptedException e) {
}
}
}
return mLooper;
}

答:不会,由于上面代码还有个(6),6是指针万用表的使用方法干啥的?等候,对,可线程池面试题是除了等候,wait()还会开释锁!!,所以一旦wait(),那么run()里边就继续实行了,所以不存在死锁,安全死锁产生的条件是:大于等于两把锁!!