ThreadLocal在Looper中的使用
来源:互联网 发布:达达妈淘宝店卖假货 编辑:程序博客网 时间:2024/06/05 10:19
1、这个class的思想,必须要理解,是的,这个class很牛逼
2、ThreadLocal也是为了解决共享数据(对象)的问题,同步锁的思路是线程不能同时访问一片内存区域,而ThreadLocal的思路是,干脆给每个线程Copy一份一抹一样的对象,各自玩自己的,互相不影响。
3、往往实例变量或者静态变量都是可以被多个线程访问的,如果一个class的行为状态可变(实例变量或静态变量),那我们就称该class是线程不安全的。如果此时一个实例变量同时(非绝对意义上的同时哈,cpu调度还是很快的)被多个线程访问,修改,这样我们的需求就不能得到满足。
4、ThreadLocal解决的问题就是,一个class,其中的一个实例变量或者一个静态变量,或者就当前class的实例对象,我们想让它(一个对象或对象中的实例变量或静态变量)在每个线程中都独立存在一份,那么ThreadLocal就可以办到,ThreadLocal可不是线程class,不要被名字所迷惑。
5、常见ThreadLocal应用场景:如何确保在每一个线程中只有一个Looper的实例对象?所谓Looper与Thread绑定,就是Looper拿到Thread的实例对象的引用。这个里面就用到了ThreadLocal。
看了下Looper源码(我们直接开撸,我写了一堆注释,为了简单一点,我把源代码中的英文注释 全部干掉)
收获:Looper重写了toString方法,我们调用toStirng,即可知道当前的Looper实例对象,是跟哪根线程绑定到一起了,也能看到哈希值
package android.os;import android.annotation.NonNull;import android.annotation.Nullable;import android.util.Log;import android.util.Printer;public final class Looper { private static final String TAG = "Looper"; // 这里ThreadLocal用的是final的静态变量(常量),所有的Looper共用一个ThreadLocal就够了 //因为ThreadLocal也是去每一个Thread中持有的元素,另外Looper的构造方法已经private了,我不能通过new一个对象了,只能静态方法能满足我 //静态方法里面,当然只能传入静态变量了(与class的加载机制有关,静态成员会有限加载到JVM中),所以ThreadLocal必须为static static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //静态成员,final的静态变量(叫常量好了,呵呵),直接初始化ThreadLocal的实例对象 private static Looper sMainLooper; // guarded by Looper.class //类变量,Looper的引用 final MessageQueue mQueue; //final的实例变量,类型是MessageQueue final Thread mThread; //final的实例变量,Thread的引用 private Printer mLogging; //实例变量,一个Printer的引用 public static void prepare() { //静态方法prepare prepare(true); //在这里又调用了重载的prepare } private static void prepare(boolean quitAllowed) { //我就是重载的prepare了 if (sThreadLocal.get() != null) { //如果ThreadLocal里面已经持有实例对象 throw new RuntimeException("Only one Looper may be created per thread"); //抛出运行时异常(每一个线程只能有一个Looper实例对象) } sThreadLocal.set(new Looper(quitAllowed)); //反之如果sThreadLocal.get()为null的话,设置Looper实例对象到ThreadLocal里面,调用了一个参数的构造方法 } public static void prepareMainLooper() { prepare(false); //调用prepare,初识一个Looper synchronized (Looper.class) { //class的Class对象锁代码块 if (sMainLooper != null) { //判断当前Looper不为null throw new IllegalStateException("The main Looper has already been prepared."); //抛出异常(主要的Looper已经有了) } sMainLooper = myLooper(); //调用myLooper静态方法,返回Looper,myLooper静态方法里面是从ThreadLocal获取的Looper实例对象 } } public static Looper getMainLooper() { synchronized (Looper.class) { //Class对象锁 return sMainLooper; //返回Looper实例对象 } } public static void loop() { //静态方法loop final Looper me = myLooper(); //先从ThreadLocal里面拿到Looper实例对象 if (me == null) { //如果没有拿到Looper实例对象,抛出异常(没有Looper;在这个线程中还没有调用过Looper.prepare()静态方法) throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; //Looper构造方法初始化了MessageQueue,这里获取该实例变量,不赋值给局部变量queue // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); //这里说是检查线程是本地线程啥的,具体是啥,老子私下搞你 final long ident = Binder.clearCallingIdentity(); for (;;) { //无限循环体,在线程的run方法里有个无限循环体,就在这里 Message msg = queue.next(); // might block可能堵塞哦 if (msg == null) { //这里是循环结束条件,Message为null,即MessageQueue里面没有Message的时候 // No message indicates that the message queue is quitting. return; } Printer logging = me.mLogging; 获得Looper的实例变量mLogging(Printer) if (logging != null) { //如果拿到Printer,就调用Printer的println() logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); //这里调用Message里面target的一个实例方法dispatchMessage,传入的还是当前的Message实例对象 if (logging != null) { //又判断了,要是有Printer,就调用它的实例方法println logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); //又要确保线程的事情 if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); //调用Message的实例方法recycleUnchecked } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); //在ThreadLocal实例对象中,调用实例方法get,得到Looper实例对象 } public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; //从Looper实例对象中得到MessageQueue实例对象 } private Looper(boolean quitAllowed) { //构造方法 mQueue = new MessageQueue(quitAllowed); //初始化一个MessageQueue实例对象,其中的局部变量quitAllowed,是从prepare方法传过来的哦 mThread = Thread.currentThread(); //得到当前线程(一个Thread的实例对象) } public boolean isCurrentThread() { //判断当前的线程,是否与初始化Looper时的线程是同一个实例对象(同一个线程) return Thread.currentThread() == mThread; //如果是同一个,返回true,否则返回false } public void setMessageLogging(@Nullable Printer printer) { mLogging = printer; //在这里设置Printer实例对象 } public void quit() { mQueue.quit(false); //MessageQueue退出 } public void quitSafely() { mQueue.quit(true); //安全退出MessageQueue } public @NonNull Thread getThread() { return mThread; //返回线程实例对象,是的,Looper实例对象初始化的时候得到的那根线程,即算Looper所谓绑定的线程 } public @NonNull MessageQueue getQueue() { return mQueue; //返回消息队列 } public void dump(@NonNull Printer pw, @NonNull String prefix) { pw.println(prefix + toString()); mQueue.dump(pw, prefix + " "); } @Override public String toString() { //重写了toSting方法,返回的字符串,还挺有价值的,秒,返回当前绑定的线程名字,线程id,当前Looper实例对象的哈希值 return "Looper (" + mThread.getName() + ", tid " + mThread.getId() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; }}
0 0
- ThreadLocal在Looper中的使用
- 由Looper中的ThreadLocal谈起--论ThreadLocal的使用
- 由Looper中的ThreadLocal谈起--论ThreadLocal的使用
- ThreadLocal 在多线程中的使用
- ThreadLocal和NIO在Tomcat6中的使用
- ThreadLocal在java web工程中的使用。
- Android -理解ThreadLocal、Looper
- Handler、Looper、ThreadLocal 、Values
- ThreadLocal在Java中的应用
- ThreadLocal在Spring中的应用
- 事务处理中的ThreadLocal的使用
- Looper、Handler在子线程中的应用
- Handler、Looper、ThreadLocal、MessageQueue、Message
- Android中Looper之ThreadLocal
- ThreadLocal在spring框架中的作用
- ThreadLocal在J2EE轻量级开发中的应用
- ThreadLocal在spring框架中的作用
- ThreadLocal在spring框架中的作用
- 自适应的一个表格
- 写给同样在路上的Android小伙伴们
- dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算
- 算法题整理
- 阿里百川HotFix二期内测 就等你来!
- ThreadLocal在Looper中的使用
- 什么是DQL、DML、DDL、DCL
- android 内存泄漏分析过程详解
- Intent连接不同组件的原理
- C#解压缩文件方法
- Scala学习笔记9 - 包和引用
- 普通管道和命名管道
- jquery ajax POST提交 例子详解
- 按钮的框框