- 实现Runnable接口
- 实现Callable接口
- 通过线程池
线程池的工作原理:线程池可以减少创建和销毁线程的次数,从而减少系统资源的消耗,当一个任务提交到线程池时
a. 首先判断核心线程池中的线程是否已经满了,如果没满,则创建一个核心线程执行任务,否则进入下一步
b. 判断工作队列是否已满,没有满则加入工作队列,否则执行下一步
c. 判断线程数是否达到了最大值,如果不是,则创建非核心线程执行任务,否则执行饱和策略,默认抛出异常
4.说下handler原理
Handler
,Message
,looper
和MessageQueue
构成了安卓的消息机制,handler
创建后可以通过sendMessage
将消息加入消息队列,然后looper
不断的将消息从MessageQueue
中取出来,回调到Hander
的handleMessage
方法,从而实现线程的通信。
从两种情况来说,第一在UI
线程创建Handler,此时我们不需要手动开启looper
,因为在应用启动时,在ActivityThread
的main方法中就创建了一个当前主线程的looper
,并开启了消息队列,消息队列是一个无限循环,为什么无限循环不会ANR
?因为可以说,应用的整个生命周期就是运行在这个消息循环中的,安卓是由事件驱动的,Looper.loop
不断的接收处理事件,每一个点击触摸或者Activity每一个生命周期都是在Looper.loop
的控制之下的,looper.loop
一旦结束,应用程序的生命周期也就结束了。我们可以想想什么情况下会发生ANR
,第一,事件没有得到处理,第二,事件正在处理,但是没有及时完成,而对事件进行处理的就是looper
,所以只能说事件的处理如果阻塞会导致ANR
,而不能说looper
的无限循环会ANR
另一种情况就是在子线程创建Handler
,此时由于这个线程中没有默认开启的消息队列,所以我们需要手动调用looper.prepare()
,并通过looper.loop
开启消息
主线程Looper
从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。
5.内存泄漏的场景和解决办法
1).非静态内部类的静态实例
非静态内部类会持有外部类的引用,如果非静态内部类的实例是静态的,就会长期的维持着外部类的引用,组织被系统回收,解决办法是使用静态内部类
2).多线程相关的匿名内部类和非静态内部类
匿名内部类同样会持有外部类的引用,如果在线程中执行耗时操作就有可能发生内存泄漏,导致外部类无法被回收,直到耗时任务结束,解决办法是在页面退出时结束线程中的任务
3).Handler内存泄漏
Handler导致的内存泄漏也可以被归纳为非静态内部类导致的,Handler内部message是被存储在MessageQueue
中的,有些message不能马上被处理,存在的时间会很长,导致handler无法被回收,如果handler是非静态的,就会导致它的外部类无法被回收,解决办法是1.使用静态handler,外部类引用使用弱引用处理2.在退出页面时移除消息队列中的消息
4).Context导致内存泄漏
根据场景确定使用Activity的Context还