从Android Handle看 线程与对象、ThreadLocal

48 篇文章 2 订阅

最近面试,对线程有了更深的理解。

问题:

 

RuntimeException:Can't create handler inside thread that has not called Looper.prepare()。(不能在没有调用Looper.prepare()的线程内创建Handler)

Looper.prepare()是为了创建Looper、MessageQueue。那为什么在工作线程new Handler,需要Loop对象,为什么UI线程就不需要。对象和线程之间是什么关系,

 

易混淆点是: 多线程时,认为对象属于某一线程。(大错,特错

对象

 

  • 本质是 内存中的数据,且具有某种固定格式
  • 数据是存在于java虚拟机中,java虚拟机用 堆、方法区来存放数据信息
  • 数据分为:类信息的描述(类的名称、方法名、父类名称)、实例数据(字段的值,如Dog类的对象 中的名字 小黑)
  • 类信息的描述 存放在虚拟机的 方法区(只是叫这个名字,和java中的方法没啥关系) 中
  • 实例数据存放在 堆(heap)中,并保存指向 类信息的指针
  • 在虚拟机中 堆、方法区 是线程共享的,也就是线程都可以操作的 

 

各线程是共享内存地址空间,共享一个 堆的、所以共享堆 产生的对象。

 

打个比方:

会计用算盘(内存)算数,算盘上拨出的数字2(Integer对象,数据)。

当用两个手(线程)操作算盘(内存)拨出2+2。

那右手动的时候,不能说2(数据)属于右手(线程)。

 

线程:

 

程序的控制流 (手操作的一组流程,当然比喻不准确),表现为一组方法。而对象是方法操作的元素。

所以每个线程的 方法栈是独立的。这样A、B两个线程才能同时执行不同的方法。

 

Handler

handler可以从工作线程提交任务,然后UI线程执行。

因为Handler对象线程共享,而它们的操作可以分开,所以并不矛盾。

 

Looper:

其实框架在加载APP时已调用了Looper.prepareMainLooper();这个操作,在ActivityThread main方法(应用入口)里做的。

那既然Looper已经有了,且对象是线程共有的。为什么还要Looper.prepare()在工作线程new Looper。

这就涉及到了ThreadLocal。Looper有个静态字段

static final ThreadLocal<Looper>sThreadLocal

 

ThreadLocal:

(算盘右边5串珠子(数据),只允许右手(指定的线程)操作)

ThreadLocal像Map。key是线程本身、value是任意对象。通过get、set方法调用。

调用set时,就会把当前Thread作为Key值。调用get时也是如此。

而Looper.prepare()调用了:

sThreadLocal.set(new Looper(quitAllowed));

  因框架启动在UI线程,所以ThreadLocal Key值是UI线程,Value为对应的Looper

 

Handler有属性Looper,new Handler---》Looper.myLooper()---->sThreadLocal.get();

因为工作线程这个Key值没有对应的Value所以就回报错。

 

解决:

所以从上面可以看出,只要Handler在new时调用 ThreadLocal能get到Looper就行。所以向Handler传Looper参数就行。

 

new Thread(){
            @Override
            public void run() {
                super.run();
                new Handler(Looper.getMainLooper());
            }
        }.start();

 

 

 

 

 

总结:

对象不存在属于某个进程这种描述,对象是数据,进程是操作流程。之所以出现工作线程需要ThreadLocal,将对象和线程产生了关联。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值