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
原创粉丝点击