ThreadLocal存取的变量只能被当前线程访问,其余线程则没法访问和修改。html
数据以线程为做用域,不一样的线程有不一样的数据副本。
各个线程往***同一个***ThreadLocal中填充的变量属于当前线程,该变量对其余线程而言是隔离的android
虽然是在不一样线程调用的local
但由于存取的map变量是在Thread内部,而且local是同一个
因此,能实现存储的变量属于当前线程,对其它线程隔离数组
<!--#:ThreadLocal-->
/**
* 实际上调用的是:各个线程中的threadLocalMap.set/getEntry
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//Thead中的ThreadLocalMap是在ThreadLocal中被建立的
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
--------------------
<!--#:Thread-->
ThreadLocal.ThreadLocalMap threadLocals = null;//在ThreadLocal中被初始化
//以local实例为索引
private void set(ThreadLocal<?> key, Object value) {}
private Entry getEntry(ThreadLocal<?> key) {}
/**
虽然是在不一样线程调用的local
但由于存取的map变量是在Thread内部,而且local是同一个
因此,能实现存储的变量属于当前线程,对其它线程隔离
*/
ThreadLocal<String> local = new ThreadLocal<>();
//#Thread$1
local.set("strValue");
String value = local.get();
//#Thread$2
local.set("strValue");
String value = local.get();
复制代码
Android多线程:HandlerThread详细使用手册
Android多线程:一步步带你源码解析HandlerThread安全
# HandlerThread:
@Override
public void run() {
Looper.prepare();
synchronized (this) {
//这步才是最主要的,让处理耗时操做的workHandler使用mLooper,这样就能在当前的子线程中处理workHandler的耗时操做了。
mLooper = Looper.myLooper();
notifyAll();
}
//空方法,loop前的准备
onLooperPrepared();
Looper.loop();
}
复制代码
protected void onCreate() {
HandlerThread handlerThread = new HandlerThread("word_handler");
handlerThread.start();
//使用子线程的Looper,因此workHandler中的耗时操做在子线程中执行
WorkHandler workHandler = new WorkHandler(handlerThread.getLooper());
mainHandler = new MainHandler();
Message msg = Message.obtain();
msg.what = 1;
workHandler.sendMessage(msg);//work发送消息
}
//和HandlerThread同线程,处理工做任务
public class WorkHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Message messag = Message.obtain();
messag.obj = "from word Handler";
mainHandler.sendMessage(messag);//通知主线程
}
}
class MainHandler extends Handler{
public void handleMessage(Message msg) {
tvTest.setText((String)msg.obj);
}
}
复制代码
protected void initData() {
mainHandler = new MainHandler();
myHandlerThread = new WorkHandlerThread("my_handler_thread");
myHandlerThread.start();
}
@OnClick({R.id.btn_start})
public void onViewClicked(View view){
Message msg = Message.obtain();
msg.what = 1;
myHandlerThread.getWorkHandler().sendMessage(msg);
}
/**
* 当前线程
*/
class MainHandler extends Handler{
@Override
public void handleMessage(Message msg) {
tvTest.setText((String)msg.obj);
}
}
/**
* 工做:处理耗时任务
*/
class WorkHandlerThread extends MyHandlerThread{
public WorkHandlerThread(String name) {super(name);}
@Override
public void workMessage(Message msg) {
Thread.sleep(2000);
Message messag = Message.obtain();
messag.obj = "from word My WordHandler";
mainHandler.sendMessage(messag);
}
}
/**
* 封装基类
*/
abstract class MyHandlerThread extends HandlerThread{
private WorkHandler mWorkHandler;
@Override
protected void onLooperPrepared() {
mWorkHandler = new WorkHandler(getLooper());
}
public WorkHandler getWorkHandler(){return mWorkHandler;}
public abstract void workMessage(Message msg);
class WorkHandler extends Handler{
public WorkHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
workMessage(msg);
}
}
}
复制代码
IdleHandler-干货集中营
你知道android的MessageQueue.IdleHandler吗?
IdleHandler,页面启动优化神器bash
是 Handler 机制提供的一种,能够在 Looper 事件循环的过程当中,当出现空闲的时候,容许咱们执行任务的一种机制多线程
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
//第一次时知足<0条件
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
//执行下面的for循环一次后,置为0,后面再到此处再也不往下执行
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
}
// We only ever reach this code block during the first iteration.
//只有第一次执行能到达
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
//置为0,后面再也不知足上面条件进入for循环
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
复制代码
Android Handler机制之总目录
Message中obtain()与recycle()的前因后果-系列异步
Android的消息机制主要是指Handler的运行机制
即:消息的发送、入队、出队、分发过程。async
Android规定访问UI只能在主线程中进行,在子线程中访问UI就会抛异常。可是Android又不建议在主线程中作耗时操做,会可能致使ANR。因此,咱们须要,能在子线程中作完耗时操做,而后去到主线程更新UI的办法。
Hander的主要做用是将一个任务切换到指定的线程中去执行。所以,系统提供Handler主要是***为了解决在子线程中没法访问UI的问题***(而不是把耗时操做放到子线程中的问题)。ide
在单线程模型中始终要记住两条法则:
一、不要阻塞UI线程
二、确保只在UI线程中访问UI
handler中有众多的send方法,时间点的区别而已,到最后都会调用下面的方法,把message放入消息队列
MessageQueue是链表结构
//消息发送
<!--#Handler-->
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//注意此处,this指的是handler本身
msg.target = this;
//把消息插入队列
return queue.enqueueMessage(msg, uptimeMillis);
}
//入队
<!--#MessageQueue-->
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//若是队列为空或者时间最小,插入到头部
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//循环队列,根据时间找到合适的位置插入
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
复制代码
loop将队列中的msg一个一个取出,分发到各自的handler中处理。
handler根据是否有callback选择不一样的分发方式。
//出队
<!--#Looper-->
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
//真正决定阻塞的是queue.next()中的for循环
for (;;) {
//next方法会阻塞线程,有消息就取出,没消息就等待。退出返回null结束当前循环。
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
//Looper.quit退出循环
return;
}
//加入消息队列时,target == handler,分发的时候就能够找到原来的handler,让其本身处理。
//因此,一个线程多个handler发送消息,虽然都在一个队列里,可是仍是会分发到原来的handler处理消息。
msg.target.dispatchMessage(msg);
}
}
//取出消息
<!--#MessageQueue-->
Message next() {
//阻塞线程
for (;;) {
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
//异步消息?
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//还不到取出时间
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 取出msg
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
//Looper.quit(),返回null。
//此时,Looper中的for循环收到null也return,退出循环
if (mQuitting) {
dispose();
return null;
}
}
}
}
//由target返回到Handler中执行分发
//加入队列的:有的是Runnable封装的message,有的是callback,有的是message,在这里分发
<!--#Handler-->
public void dispatchMessage(Message msg) {
//runnable封装的message。 handler.post/view.post
if (msg.callback != null) {//msg中的callback 优先级1
handleCallback(msg);
} else {
if (mCallback != null) {
//Handler(Callback callback)的时候,mCallback !=null
if (mCallback.handleMessage(msg)) {//handler中的callback,优先级2
return;
}
}
//正常的message那种形式,也便是new Handler时复写的方法。
handleMessage(msg);// 优先级3
}
}
复制代码
<!--#Looper-->
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
<!--#Handler-->
public Handler(Callback callback, boolean async) {
//验证当前线程有没有Looper对象,因此new以前要prepare存入
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
}
<!--#:Thread1-->
Looper.prepare()//当前线程存
Handler handler = new Handler();//当前线程取
Looper.loop();
<!--#:Thread2-->
Looper.prepare()//当前线程存
Handler handler = new Handler();//当前线程取
Looper.loop();
<!--#:Thread3-->
Looper.prepare()//当前线程存
Handler handler = new Handler();//当前线程取
Looper.loop();
复制代码
为何主线程 new Handler以前不用prepare,也不用loop?
UI线程是主线程,系统已经自动帮咱们调用了Looper.prepare()和Looper.loop()方法
复制代码
优先级1:
<!--封装成Message,放入队列-->
//view.post(runnable)和handler.post(runnable)
//最后runnable都会分装成Message。分发的时候,在第一处调用。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
<!--分发调用-->
private static void handleCallback(Message message) {
message.callback.run();
}
注意:虽然是runnable,但并非新的线程。
此处的run()就是正常的方法,Runnable中不要作耗时操做。
复制代码
优先级2:
public Handler(Callback callback, boolean async) {
...
mCallback = callback;
...
}
复制代码
优先级3:
经常使用的发送Message方式,设置what,obj参数,发送的消息。
<!--#MessageQueue-->
void quit(boolean safe) {
//主线程时,quit报错
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
//mQuitting该标记使next方法中返回null,使loop结束循环。
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
}
}
Message next() {
//MessageQueue的next返回null,就能结束loop循环了
if (mQuitting) {
dispose();
return null;
}
}
public static void loop() {
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
/*
* 不是指消息队列里没有消息了(没有消息,队列也会一直循环)
* 是调用了Loop的quit()、quitSafely()方法,结束循环
*/
if (msg == null) {
//退出循环
return;
}
...
}
}
复制代码
<!--#MessageQueue-->
void quit(boolean safe) {
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
}
//回收全部消息
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
//回收延迟消息
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;
}
//找到 <= now的msg ==> p
p = n;
}
//把p之后的消息回收
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
复制代码
quit()方法的做用:
1_标记mQuitting = true,使next方法返回null,结束循环。
2_移除消息队列中的消息。
源码中能够看到,子线程中preaper时候,默认设置为true。
主线程中:prepareMainLooper的时候,默认是false。
因此,子线程的Loop是能够quit的,而主线程的不能够。
//app入口 ActivityThread
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
...
Looper.loop();
}
public static void prepareMainLooper() {
prepare(false);
...
}
//初始化MessageQueue时设置
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
void quit(boolean safe) {
//这个地方:主线程时,quit报错
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
...
}
复制代码
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
//非UI线程,到主线程的handler执行
mHandler.post(action);
} else {
//UI线程直接run
action.run();
}
}
复制代码
Handler内部类引用Activity,msg.target = this引用handler,形成内存泄漏
/**
为避免handler形成的内存泄漏
一、使用静态的handler,对外部类不保持对象的引用
二、但Handler须要与Activity通讯,因此须要增长一个对Activity的弱引用
*/
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityReference;
MyHandler(Activity activity) {
this.mActivityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = (MainActivity) mActivityReference.get(); //获取弱引用队列中的activity
//若引用,判断null
if(activity != null && !activity.isFinish()){
byte[] data = (byte[]) msg.obj;
activity.threadIv.setImageBitmap(activity.getBitmap(data));
break;
}
}
复制代码
Android中为何主线程不会由于Looper.loop()里的死循环卡死
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler();
Looper.loop();
Log.d("loop()是死循环,阻塞线程,后面的代码不执行");
}
}
复制代码
#ActivityThread:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
#1
ActivityThread thread = new ActivityThread();
#2
thread.attach(false);
if (sMainThreadHandler == null) {
#3
sMainThreadHandler = thread.getHandler();
}
#4
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
复制代码
Android的各个生命周期和事件,都是在loop循环中接收、处理消息的。引发ANR是由于处理消息时阻塞了,而不是由于loop循环阻塞的。
其实否则,这里就涉及到Linux pipe/epoll机制;
简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,详情见Android消息机制1-Handler(Java层),此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,经过往pipe管道写端写入数据来唤醒主线程工做。
这里采用的epoll机制,是一种IO多路复用机制,能够同时监控多个描述符,当某个描述符就绪(读或写就绪),则马上通知相应程序进行读或写操做,本质同步I/O,即读写是阻塞的。
因此说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
#HandlerActionQueue:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
//若是当前View加入到了window中,直接调用UI线程的Handler发送消息
return attachInfo.mHandler.post(action);
}
//View未加入到window,放入HandlerActionQueue的mActions(数组)中
getRunQueue().post(action);
return true;
}
#View:
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//View加入window后,直接执行mActions保存的
mRunQueue.executeActions(info.mHandler);
}
复制代码