ThreadLocal、Looper、Handler、MessageQueue
一、ThreadLocal
线程局部存储(ThreadLocalStorage)当从同一线程中引用该变量时,其值总是相同;而从不同的线程中引用该变量时,其值应该不同。
作用域:
方法成员变量:仅在方法内部有效
类成员变量:仅在对象内部有效
线程局部存储(TLS)变量:在本线程内的任何对象内保持一致
静态变量:在本进程内的任何对象内保持一致
跨进程通信(IPC)变量:一般使用 Binder 定义,在所有进程中保持
二、Looper
./frameworks/base/core/java/android/os/Looper.java
作用:
1、调用该类中的静态方法 prepare() 创建一个消息队列
在 Looper 的静态方法 prepare() 中,给线程局部存储变量中添加一个新的 Looper 对象:
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
Looper 的构造方法中创建了一个 MessageQueue 对象:
private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }
2、提供静态方法 loop() ,使调用该方法的线程进行无限循环,并从消息队列中读取消息
对程序员来讲,当需要把一个线程变为异步消息处理线程时,应该在 Thread 类的 run() 方法中先调用 Looper.prepare() 为该线程创建一个 MessageQueue 对象,然后再调用 Looper.loop() 方法,使当前线程进入消息处理循环
1 public static final void loop() { 2 Looper me = myLooper(); 3 MessageQueue queue = me.mQueue; 4 while (true) { 5 Message msg = queue.next(); // might block 6 //if (!me.mRun) { 7 // break; 8 //} 9 10 if (msg != null) { 11 if (msg.target == null) { 12 // No target is a magic identifier for the quit message. 13 return; 14 } 15 if (me.mLogging!= null) me.mLogging.println( 16 ">>>>> Dispatching to " + msg.target + " " 17 + msg.callback + ": " + msg.what 18 ); 19 20 msg.target.dispatchMessage(msg); 21 22 if (me.mLogging!= null) me.mLogging.println( 23 "<<<<< Finished to " + msg.target + " " 24 + msg.callback); 25 26 msg.recycle(); 27 } 28 } 29 }
1)调用 myLooper() 函数返回当前线程的 Looper对象,调用 sThreadLocal.get() 方法返回当前线程 ID 对应的 Looper 对象
public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }
2)通过 Looper 对象获取线程的消息队列
MessageQueue queue = me.mQueue;
3)进入 while 无限循环
(1)调用MessageQueue 对象的 next() 方法取出队列中的消息(如果当前队列为空,则当前线程会被挂起,也就是说 next() 内部会暂停当前线程)
Message msg = queue.next();
(2)回调 dispatchMessage(msg) 完成对消息的处理。msg 变量的类型是 Message, msg.target 的类型是 Handler
msg.target.dispatchMessage(msg);
(3)处理完消息后,调用 msg.recycle() 回收 Message 对象占用的系统资源。因为 Message 类内部使用了一个数据池保存 Message 对象,从而避免不停的创建和删除 Message 对象,因此每次处理完该消息后需要将 Message 对象表明为空闲状态
三、MessageQueue
./frameworks/base/core/java/android/os/MessageQueue.java
1、消息在 MessageQueue 中以 Message 表示,消息以链表的结构进行保存
2、MessageQueue 中两个主要的方法“取出消息”和“添加消息”
1)取出消息 next()
final Message next() { ... // Try to retrieve the next message, returning if found. synchronized (this) { now = SystemClock.uptimeMillis(); Message msg = pullNextLocked(now); if (msg != null) return msg; if (tryIdle && mIdleHandlers.size() > 0) { idlers = mIdleHandlers.toArray(); } } ... }
2)添加消息 enquenceMessage()
final boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
四、Handler
./frameworks/base/core/java/android/os/Handler.java
1、尽管 MessageQueue 提供了直接读/写的函数接口,但对于应用程序员而言一般不直接读/写消息队列。在Looper.loop() 函数中,当取出消息后回调 msg.target 的 handleMessage() 方法,而 msg.target 的类型正是 Handler。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
我们一般用 Handler 类向消息队列中发送消息,并重载 Handler 类的 handleMessage() 函数添加消息处理代码。
2、Handler 对象只能添加到有消息队列的线程中,否则发生异常
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()"); }
因此,在构造 Handler 对象前必须已经执行过 Looper.prepare() ,但 Looper.prepare() 不能被执行两次。
五、UI线程和自定义 Thread的区别
1、UI线程是从 ActivityThread 运行的,在 ActivityThread 中的 main() 方法中已经使用 Looper.prepareMainLooper() 为线程添加了 Looper 对象(即已经创建了消息队列MessageQueue)
2、自定义 Thread 是一个裸线程,因此不能直接在 Thread 中定义 Handler对象