多线程
进程:
1、程序(任务)的执行过程。动态性。
2、持有资源(共享内存、共享文件)和线程。载体。
线程:
1、线程是系统中的最小执行单元
2、同一进程中有多个线程
3、线程共享进程的资源
Thread常用方法
备注:public class Thread implements Runnable,所以Thread.java其实是实现了Runnable接口。
类别
方法
简介
线程的创建
Thread()
Thread(String name)
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, String name)
线程的方法
synchronized void start()
启动线程
void run()
Calls the run() method of the Runnable object,否则什么都不做
static void sleep(long millis)
线程修眠
static void sleep(long millis, int nanos)
final void join()
使其他线程等待当前线程终止
final void join(long millis)
final void join(long millis, int nanos)
static native void yield()
当前运行线程释放处理器资源
void destroy()
deprecated
final void stop()
deprecated
停止线程,但该方法已删除。
推荐停止:退出标志位
final synchronized void stop(Throwable obj)
deprecated
void interrupt()
deprecated
static native boolean interrupted()查询interrupt status,清除flag的副作用。
native boolean isInterrupted()
查询interrupt status。
中断,但是在Object.wait()、join()、sleep()中使用该方法,将会唤醒线程,并且清除interrupt status,收到InterruptedException。
获取线程引用
static native Thread currentThread()
返回当前运行线程的引用
查询线程是否alive
final boolean isAlive()
has already been started and still runs,return true
Thread、Looper、Handler小结
线程的本质都是实现了Runnable接口。
线程的本质是另外申请资源。
Looper有消息队列。Looper是消息循环的主体,负责循环从MessageQueue中获取需要处理的新消息并向Handler输送。
Handler内部都实现了Runnable接口,所以该类内部也有线程。
Handler有Looper,既而有消息队列,也才能实现循环处理事务。Handler的有参构造方法,保存了Looper,MessageQueue等实例,可以说明Handler是直接依赖于Looper的。
Handler发送和处理接收到的消息,其背后有一个消息循环为它管理和提供消息。
Handler可通过IMessenger和Message来实现进程间的消息传递。Message本身实现了Parcelable接口支持跨进程,Handler中定义了继承IMessenger.Stub的MessengerImpl类作为跨进程传入Message的入口。进程外通过Handler.getIMessenger()方法获得此Handler的IMessenger即可向它发送消息。
Handler提供了post和sendMessage方法,使得线程能按照一定节奏处理事务(事务抛给自己的线程处理);也能实现异步,让其他线程给处理(事务抛出让其他线程处理),即线程间通信。
Handler提供了dispatchMessage方法,专门自己和其他线程的事务。
HandlerThread继承自Thread,但其实是Handler+Thread,所以HandlerThread内部有线程、消息队列、有事务抛出和处理方法,能循环处理事务,也能实现异步处理,更能实现子线程和子线程间的通信(Handler+Thread也可以达到同样的效果,只是要操作Looper)。
Handler
根据google的注释,Handler的2个主要用途:
1. 让Message和Runnable可以延迟执行;
2. 在另外一个线程中执行处理。
用法:
通过Post开头和sendMessage开头的方法可以发送消息到MessageQueue。
1. post开头的方法可以向队列插入Runnable;
2. sendMessage开头的方法则用于来送Message,Message将在handleMessage方法中被处理。
3. post和send方法既可以让消息“实时”被处理(相对于延时),也可以设置特定的时延,延时去处理。
建议:
应用进程中的的主线程是专门用于管理顶层的数据的,例如activity/广播/窗口等,不宜处理其他我们定义的耗时操作,因此我们应该创建自己的工作线程,通过Handler来向线程的MessageQueue发送要执行的任务。
注意:
1、Looper.prepare()内部新建了Looper实例,并set到sThreadLocal,那么,就足以解释为什么在new Handler()之前必须调用Looper.prepare()。
——因为Handler需要获取到Looper实例,而Looper.prepare()就是创建Looper的地方。
2、Looper.loop()方法内部是个死循环,循环从MessageQueue中获取消息并分发给Handler,因此loop()方法必须是最后执行的。
3、Handler初始化是必须获得Looper的,而Looper只有在Looper.prepare()方法中创建。顺藤摸瓜,在Looper.java中找到了一个叫prepareMainLooper的方法,不仅创建了Looper对象,而且将它保存到了sMainLooper变量中。搜索下Looper.prepareMainLooper()的调用者,竟然是ActivityThread.main()方法。就是说,在Activity创建的时候,主线程创建了自己的main looper,并同样地开启了无限循环模式!这侧面映证了Android应用运行是靠消息驱动的。
4、Looper的消息循环是死循环,因此一个Thread中只能运行一个Looper。而Handler作为消息的发送和处理者,与Looper的关系是多对一的。
因此它们3者的关系是: 1 Looper - 1 Thread - N
Handler
5、post的是Runnable,一般是自己线程处理,而且入口是同一个函数(虽然可能每次做的事不同,但是外部看是跑的同一个方法);发送消息既可以自己处理,也可以其他线程处理,一般根据消息处理不同,有所选择(虽然入口也是同一个方法,消息处理方法,但是消息有具体匹配,可以进行详细划分)。
Handler使用
1、定义在子线程的Handler
主线程:
new MyThread().start();
//确保Handler已经在子线程中实例化
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
子线程核心:
MyThread extends Thread{//该类是内部类
@override
public void run() {
Looper.prepare();
mHandler = new Handler();//mHandler是全局变量,创建在子线程
Looper.loop();
}
2、定义在主线程的Handler
mHandler = new Handler();//Handler声明、创建在主线程中
new MyThread().start();
class MyThread extends Thread{//内部类
@Override
public void
run() {
mHandler.post(new Runnable() {//在线程的run中post一个Runnable
@Override
public void
run() {
Log.i("handler.demo", "Running in Thread:" +
Thread.currentThread().toString());
}
});
Message
Message是一个数据类,包含用户定义的数据,Runnable实例,关联的Handler。
同时,下一个Message的实例保存在next变量中,可见Message将以链的形式保存。
Message中还实现了消息重用,如果使用Message.obtain()方法获取Message,将返回可重用的Message。
循环从MessageQueue.next()中获取消息,这里先来看消息的分发:Handler.dispatchMessage():
1. 如果通过post(Runnable)发送的Message,那么只执行Runnable.run()。
2. 如果如果实现了Handler.Callback接口,则消息分发给Callback.handleMessage()方法处理,返回ture就不会执行第三步
3. 由Handler.handleMessage()处理
获取消息:MessageQueue.next()方法
MessageQueue的next方法也是一个循环,主要目的是获取下一个要被处理的Message,其中的几个要点:
1. nativePollOnce是阻塞的,中间执行了epoll_wait等待,通过nativeWake主动唤醒或者到达超时时间后唤醒。
2. 如果插入了SyncBarrier消息(handler为null的消息),则只会处理“异步”的消息(设置了Asynchronous flag的消息,另议)
3. 如果当前消息没有到达when设定的时间,则会重新进入nativePollOnce,设置具体的超时时间
4. 到达设定时间的Message会被返回,由Looper分发处理。
5. 如果进入next()时没有消息要被马上处理,则会执行IdleHandler的处理。
忽略IdleHandler和nextPollTimeoutMillis值的影响,大概流程如下:
插入新的Message
Handler通过post和sendMessage方法向MessageQueue发送Runnable或者Message,实际上最后都会被封装成Message,通过MessageQueue.enqueueMessage()方法加入到消息链表。
MessageQueue.enqueueMessage方法接收新的消息,通过消息延迟的时间将其插入到正确的位置。
插入消息后,有条件地执行nativeWake去唤醒epoll。needWake的值依赖mBlocked——当进入next()方法时没有待处理的消息,mBlock为true,有消息并返回到looper时,mBlock为false。
结合next()和enqueueMessage()方法,得知nativeWake被调用的条件为:
1. next()方法在等待新消息,且新插入消息的为链表头时。needWake为true
2. 设置了Sync Barrier,且插入的消息是“异步”的。needWake为true
核心流程大概分析完成:
1. java层的looper循环调用MessageQueue.next()获取下一个消息来处理;
2. next()方法进入native层nativePollOnce方法,Looper.cpp进入epoll_wait等待fd被唤醒
3. Handler向MessageQueue插入消息后,有条件地唤醒native looper,使next()方法返回
4. Looper在获取到新消息后分发处理。
关于SyncBarrier
首先,Message中有“同步”和“异步”的概念(貌似实际上只是个状态的区分,主要作用时配合SyncBarrier,并没有同步性上的区别),使用setAsynchronous方法设置。
而通过postSyncBarrier()方法,可以发送一个synchronization barrier(就直译称为“同步栏”吧)到Message链表中,用来暂停在同步栏之后发送的“同步”消息的处理,此时只有“异步”的消息能被继续处理。 设置同步栏后必须在条件准备好后移除它(调用removeSyncBarrier()方法)。
这个机制的作用在于可以马上暂停执行“同步”消息,直到条件允许后通过移除同步栏来恢复“同步”消息的处理。例如在View.invalidate需要执行时,将会设置同步栏挂起所有“同步”消息,直到下一帧准备好显示后移除同步栏。
而设置“异步”消息则可以免受同步栏的影响,用于接收输入等需要持续的工作:
置同步栏就是插入一个不指定handler的Message,通过一个token值来标记
移除同步栏时通过token值匹配并删除该Message。