关于一个thread只能创建一个looper的疑问

zm骚年 2017-05-04 02:17:34

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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));
}


sThreadLocal 是一个静态变量,如果一个线程调用了prepare()之后,sThreadLocal 不就已经保存了Looper对象了吗?
如果再次在别的线程用prepare()肯定会执行 throw new RuntimeException("Only one Looper may be created per thread");抛出异常的啊。

我觉得应该是,只能有一个线程调用prepare(),请指教
...全文
753 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
cloudwinter 2018-01-03
  • 打赏
  • 举报
回复
虽然Looper中的 ThreadLocal是静态变量,但是你看ThreadLocal中的set 和 get方法,针对不同的线程是存放在不同的ThreadLocalMap中,这样就保证了在当前线程中get的唯一性,具体可以看下ThreadLocal的源码
Demons_by 2017-05-09
  • 打赏
  • 举报
回复
没事啦~我也是喜欢没事看看源码玩~
zm骚年 2017-05-09
  • 打赏
  • 举报
回复
引用 4 楼 heaimnmn 的回复:
具体的业务场景是什么?
子线程通知主线程更新ui的时候用到
zm骚年 2017-05-09
  • 打赏
  • 举报
回复
引用 3 楼 Demons_by 的回复:
个人觉得你说的没错,然而一个thread只能创建一个looper这句话也没错,来看下图: 实际上你外部调用静态方法Looper.prepare()的时候,就是在给sThreadLocal中set一个Looper对象,这个Looper对象在被实例化的时候,在其构造器中已经定义好了消息队列和线程信息,看下图: 之后调用Looper.loop()的时候,这个myLooper的获取是从sThreadLocal中get的,看下图: 也就是说,如果你在同一线程中执行了多次Looper.prepare(),实际上也就是向sThreadLocal中set了多个looper对象,然后就会报异常。 表述的比较乱,楼主见谅 =。=
android新人第一次提问,算是体会到点什么了。前几天刚发的,现在看看又忘了点,谢谢你的回答啊,又是截图又是分析的,非常感谢。
哎,真难 2017-05-05
  • 打赏
  • 举报
回复
具体的业务场景是什么?
Demons_by 2017-05-05
  • 打赏
  • 举报
回复
个人觉得你说的没错,然而一个thread只能创建一个looper这句话也没错,来看下图:
实际上你外部调用静态方法Looper.prepare()的时候,就是在给sThreadLocal中set一个Looper对象,这个Looper对象在被实例化的时候,在其构造器中已经定义好了消息队列和线程信息,看下图:
之后调用Looper.loop()的时候,这个myLooper的获取是从sThreadLocal中get的,看下图:
也就是说,如果你在同一线程中执行了多次Looper.prepare(),实际上也就是向sThreadLocal中set了多个looper对象,然后就会报异常。
表述的比较乱,楼主见谅 =。=
zm骚年 2017-05-04
  • 打赏
  • 举报
回复

public void set(T value) {
        Thread currentThread = Thread.currentThread();    //获取当前线程
        Values values = values(currentThread);    //读取线程成员变量localValues
        if (values == null) {
            values = initializeValues(currentThread);    //初始化该线程localValues,并重新读取
        }
        values.put(this, value);    //添加该Looper对象
    }

public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();    //获取当前线程
        Values values = values(currentThread);    //读取线程成员变量localValues
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];    //如果之前已经执行prepare(),此处返回不为空,导致再次执行prepare()抛出异常
           
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this); 
    }
这是修改过来的,之前的弄错了
zm骚年 2017-05-04
  • 打赏
  • 举报
回复

public void set(T value) {
        Thread currentThread = Thread.currentThread();    //获取当前线程
        Values values = values(currentThread);    //读取线程成员变量localValues
        if (values == null) {
            values = initializeValues(currentThread);    //初始化该线程localValues,并重新读取
        }
        values.put(this, value);    //添加该Looper对象
    }

public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();    //获取当前线程
        Values values = values(currentThread);    //读取线程成员变量localValues
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this);    //这句看意思应该是null   太长了,懒得看^_^
    }
没人回复,只能靠自己啦,看看写的还能不能对别人有些帮助

80,351

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧