一,Android 进程和线程
进程-Process 是程序的一个运行实例,以区别于“程序”这一静态的概念,线程-Thread则是cpu调度的基本单位。
Android中的程序和进程具体是个什么概念呢?
对于Android的应用程序来说,通常接触的都是Activity,Service,Receive,ContentProvider等组件,很容易认为系统的四大组件就是进程的载体,实际上,它们不能算是完整的进程实例,最多只能算是进程的组成部分,从AndroidManifest.xml中可以看出,在这些组件的最外围还有一个application 标签,四大组件只是 application 的零件。我们以一个有IDE向导生成的简单的工程来看看一个应用中的进程和线程。
在自动生成的源码中MainActivity.java中的onCreate()函数入口处加上断点,如图:
那么,这个Activity启动后,会产生几个Thread 呢,如图:
除了我们熟悉的main thread外,还有2个Binder Thread,因为应用程序启动过程中需要跟系统进程ActivityManagerService、WindowManagerService等通信,需要Binder线程。那么主线程是怎么产生?可以看到主线程是有ZygoteInit启动,经过一系列的调用最终执行了Activity本身的onCreate()函数,从这里知道,主线程就是ActivityThread。
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper(); 主线程会调用这个函数,普通线程调用prepare()
ActivityThread thread = new ActivityThread();
thread.attach(false); 这个函数将于windowManagerService 建立联系,因为Activity是有界面显示的
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();主线程对应的handler
}
Looper.loop(); 主循环开始
}
在ActivityThread内部,还有一个ApplicationThread,这个ApplicationThread是应用进程跟ActivityManagerService进行跨进程通信的桥梁,比如AMS启动一个Activity,实际是先由ApplicationThread的scheduleLaunchActivity,然后到ActivityThread的performLaunchActivity。
实际上,所有应用程序的主线程都是Activity Thread,这里使用的组件是Activity,如果换成Service也是一样的,并且在一个应用程序中,主线程只有一个,对于同一个AndroidManifest.xml中定义的组件,除非有特别的指明(可以指定一个组件运行在某个进程空间,使用android:process属性,也可以在<application>标签中加入这个属性,指明想要依存的进程环境),否则它们都运行于同一个进程中。
二,Handler,MessageQueue,Runnable,Looper
1,Handler 代码路径:framework/base/core/java/android/os/Handler.java
public class Handler{
final MessageQueue mQueue;
final Looper mLooper;
IMessenger mMessenger;
final Callback mCallback;。。。
}
这里提到的几个主要元素的关系,简单说就是:Looper 不断从MessageQueue中取出消息message,然后交给Handler来处理。
每个Thread只对应一个Looper
每个Looper只对应一个MessageQueue
每个MessageQueue中有N个Message
每个Message最多指定一个Handler来处理事件
每个Thread可以对应多个Handler
Handler是经常会使用到的一个类,主要有两个方面的作用:一是处理Message,二是将某个message压入messageQueue中。Looper从MessageQueue中取出一个Message后,首先会调用Handler.dispatchMessage进行消息派发,默认的派发流程:
/**
*Handle system messages here.
*/
publicvoid dispatchMessage(Message msg) {
if(msg.callback != null) {
handleCallback(msg);
}else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
由这个函数看出,Handler的扩展子类可以通过重载dispatchMessage或handleMessage来改变它的默认行为。
处理优先级是消息本身的callback,最有优先权,其次是handler的callback,
其中msg的callback是在其生成Message对象时设置的,比如post(Runnable r)时,会先把runnable转成message,同时把runnable设置为msg的callback;
handler的callback是在实例化handler对象时。作为Handler的构造函数的参数,传入的一个实现了Handler.Callback的对象。
把一个消息压入消息队列的相应功能函数:
public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)。。。
以第一个函数为例:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}首先要把Runnable 对象,封装成一个Message,接着通过对应的send函数推送到messageQueue中,
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}这里将Runnable对象设置为Message的回调。
整个过程中,message通过handler压入messagequeue中,然后由looper从messagequeue中取出消息,还是交给了handler来处理,为什么不直接操作,而是大费周折的转了这么一圈?这里体现了程序设计的一个良好习惯“有序性”。
2,MessageQueue,源码路径:frameworks/base/core/java/android/os/MessageQueue.java
就是一个消息队列,具有“队列”的一些常规操作:
新建队列:由本地方法nativeInit来完成。
元素入队: boolean enqueueMessage(Message msg, long when)
元素出队:Message next()
删除元素:void removeMessages(Handler h, int what, Object object)
3,Looper,源码路径:frameworks/base/core/java/android/os/
从Looper的源码看出,Looper中包含了一个MessageQueue队列。
使用Looper的线程,有三个步骤:
1)Looper的准备工作(prepare
2)创建处理消息的Handler
3)Looper开始运作(loop)
首先:Looper.prepare() Looper中有一个很重要的成员变量,
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();ThreadLocal对象是一个特殊的全局变量,因为它的“全局”性只限于自己所在的线程,而外界的线程(即使在同一进程)一概无法访问到他,这从侧面说明,每个线程的Looper都是独立的。它实际就是针对每个Thread的特定数据存储空间。
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));
}
这个函数里的判断保证了一个Thread只会有一个Looper实例存在,sThreadLocal创建了一个只针对当前线程的Looper对象。
在使用Looper的线程里,肯定会创建Handler对象,所以mHandler是Thead实现类的成员变量,那么,Handler如何与Looper关联起来的呢?从Handler的构造函数分析:
public Handler()
public Handler(Callback callback)
public Handler(Looper looper, Callback callback)
public Handler(Looper looper, Callback callback, boolean async)
之所以有这么多构造函数,是因为Handler有如下内部变量需要初始化:
final MessageQueue mQueue;
final Callback mCallback;
以其中一个构造函数为例:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); //
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
mLooper = Looper.myLooper(); 还是通过sThreadLocal.get来获取当前线程中的Looper实例。
mQueue = mLooper.mQueue; mQueue是Looper跟handler之间沟通的桥梁。这样Handler和Looper,MessageQueue就联系起来了,后续Handler执行post/send系列函数时,会将消息投递到mQueue也即是mLooper.mQueue中。
3,UI主线程 Activitythread
源码路径:frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
注意区别,普通线程调用prepare(),这里调用prepareMainLooper(),主线程的Handler是从当前线程中获得的thread.getHandler();。
public static void prepareMainLooper() { //这个是Looper.java中的方法
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}prepareMainLooper也需要调用prepare,参数false表示该线程不允许退出。经过prepare后,myLooper就得到一个本地线程<ThreadLocal>的Looper对象,然后赋值给sMainLooper,从这里看,主线程和其他线程的Looper对象没有本质的区别。
作为主线程,它这么做的目的,就是其他线程如果要获取主线程的Looper,只需要调用getMainLooper()即可。
作为普通线程,它生成的Looper对象,只能在线程内通过myLooper()访问。
在来看下Looper.loop的是实现,也是Looper.java中的方法
public static void loop() {
final Looper me = myLooper(); 函数myLooper()则是调用sThreadLocal.get()来获取与之匹配的Looper实例,其实就是取出在prepare中创建的那个Looper对象。
final MessageQueue queue = me.mQueue; //Looper中自带了一个MessageQueue
for (;;) {
Message msg = queue.next(); // might block从MessageQueue中取出消息,可能会阻塞,如果当前消息队列中没有消息,说明线程要退出了
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg); 开始分发消息,这里的target就是一个handler,所以dispatch最终调用的是handler中的处理函数
msg.recycleUnchecked(); 消息处理完毕,进行回收
}
}
在来看一个函数,Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //new 了MessageQueue,也就是Looper在创建是,消息队列也同时被创建出来
mThread = Thread.currentThread(); Looper与当前线程建立了对应关系
}
4,Thread类
1)Thread类的内部原理,源码路径 libcore/libart/src/main/java/java/lang/Thread.java
public class Thread implements Runnable{
Thread实现了Runnable,也就是说线程是“可执行的代码”。
libcore/libuni/src/main/java/java/lang/Runnable.java Runnable是一个抽象的接口,唯一的方法就是run方法
public interface Runnable {
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {@code Runnable}.
*/
public void run();
}
通常我们是这样使用Thread的:
方法1,定义一个类继承自Thread,重写它的run方法,然后调用start
MyThread thr= new Mythread();
thr.start();
方法2,直接实现Runnable,
new Thread(Runnable target).start();
两种方法都是通过start启动,它会间接调用run方法,
public synchronized void start() {
checkNotStarted();
hasBeenStarted = true;
nativeCreate(this, stackSize, daemon); 这里是真正创建一个cpu线程的地方,在此之前,一直都是运行在“老线程”中,实际上在新线程中运行的只有Run方法。
}
2)Thread的休眠与唤醒,来看一下与此相关的控制方法:
首先是:wait notify notifyAll,这三个函数是Object类定义的,意味着它们是任何类的共有“属性”,下面的方法是Handler.java中的内部类:BlockingRunnable的,涉及到等待时,会调用它
public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}这个函数在Handler中的作用就是“投递并等待”,所以函数开头就把一个runnable(this)post到了handler所在的looper中。如果timeout大于0,说明是有条件限制的等待,这样可以避免异常时间下的“死等”;如果timeout等于0,无限期等待,直到有人来唤醒他。线程进入等待调用的是wait(),唤醒他就是notify/notifyAll,那么什么时候执行的唤醒操作呢?
private static final class BlockingRunnable implements Runnable {
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll(); BlockingRunnable 对象在执行run函数时,同时也做了这个特殊的操作,通知所有在等待的人,我运行OK了。
}
}
}
然后,interrupt,如果说wait是一种“自愿”的行为,那么interrupt就是*的了,调用一个线程的interrupt这个方法,就是中断它的执行过程。
join方法的几个原型:
public final void join()
public final void join(long millis)
public final void join(long millis, int nanos)
比如:Thread t1;Thread t2;
t1.start();
t1.join();
t2.start(); 它希望的目的是只有当t1线程执行完成时,才接着执行后面的t2.start(),这样就保证了两个线程的顺序执行。带有参数的join多了一个限制,假如在规定的时间内t1没有执行完成,那么会继续执行后面的语句,防止无限等待。
最后,sleep方法,它和wait类似,都属于自愿的行为,只是wait是等待某个object,而sleep则是等待时间,一旦设置的时间到了就会被唤醒。