线程分别主线程和子线程。在Android中,主线程也就是UI线程。
在Android中,除了Thread本身以外,在Android中扮演线程角色的还有很多:
AsyncTask、IntentService以及HandlerThread。
对AsyncTask来说,底层使用了线程池。对与IntentService和HandlerThread来说,它们的底层则直接使用了线程。
HandlerThread是一种特殊的线程,具有消息循环的线程,在它内部可以直接使用Handler。
IntentService是一个服务,系统对其进行了封装,使其可以更方便地执行后台任务,IntentSerivce内部采用了HandlerThread来执行任务,当任务执行完毕后IntentService会自动退出。从任务执行的角度来看,IntentService的作用很像一个后台线程,但是IntentService是一种服务,它不容易被系统杀死从而可以尽量保证任务的执行。
一、AsyncTask
AsyncTask是一种轻量级的异步任务,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程,并在主线程中更新UI。
AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数。
同时提供了以下四个核心方法:
1.onPreExecute
2.doInBackground
3.onProgressUpdate
4.onPostExecute
外加onCancelled方法。
以上方法都是在主线程里执行,除了doInBackground是在子线程。
AsyncTask在使用过程中,需要注意的以下几个点:
1.AsyncTask的类必须在主线程中加载。
2.AsyncTask的对象必须在主线程中创建。
3.excute方法必须要在主线中调用。
4.不要在程序中直接调用onPreExcute()、onPostExcute()、doInBackground和onProgressUpdate方法,因为这些方法都是callback
5.一个AysncTask对象只能执行一次,即只能调用一次execute,否则会报错。
6.在Android1.6之前,AysncTask是串行执行任务,在Android1.6的时候AysncTask开始采用线程池处理并行任务,但是从Android3.0开始,又回归到串行执行任务。如果需要你并行的话,可以调用executeOnExecutor方法来并行地执行任务。
AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正地执行任务。InternalHandler用于将执行环境从线程池切换到主线程。
二、HandlerThread
HandlerThread继承了Thread,它是一种可以使用Handler的Thread,它的实现如下:
在run 方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。
允许在HandlerThread中创建Handler,在创建Handler时,可以直接使用HandlerThread里面的Looper。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
三、IntentService
IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,因此必须创建它的子类才能使用IntentService。IntentService可用于执行后台耗时的任务,当任务执行后它会自动停止。IntentService的优先级比单纯的线程要高很多。
IntentService封装了HandlerThread和Handler
@Deprecated
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
IntentService仅仅是通过mServiceHandler发送了一个消息,这个消息会在HandlerThread中被处理。mServiceHandler收到消息后,会将Intent对象传递给onHandleIntent方法去处理。
private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } }
注意这个intent对象的内容和外界的startService(intent)中的intent的内容是完全一致的,通过这个Intent对象即可解析出外界启动IntentService时所传的参数。
@Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
当onHandleIntent方法执行结束后,IntentService会通过stopSelf(int startId)方法来尝试停止服务。
这里采用stopSelf(int startId)而不是stopSelf()来停止,那是因为stopSelf()会立刻停止服务,而这个时候可能还有其他消息未处理,stopSelf(int startId)则会等待所有的消息都处理完毕后才终止服务。
stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务,不相等则不停止服务。
这是因为每执行一个后台任务就必须启动一次IntentService,而IntentService内部则通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,这就意味着IntentService也是顺序执行后台任务的。
四、Android中的线程池
线程池的优点:
1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
2.能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
3.能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。
Android中的线程池的概念来源于Java中的Executor,Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor。ThreadPoolExecutor提供了一系列参数来配置线程池。
ThreadPoolExecutor的参数:
corePoolsize, maximumPoolSize, keepLiveTime, Unit, workQueue, threadFactory
corePoolsize 核心线程数,核心线程会在线程池一直存活,哪怕处于闲置状态。
maximumPoolSize 线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务将会被阻塞。
keepLiveTime 非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。当ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,keepLiveTime同样会作用于核心线程。
unit keepLiveTime的时间单位
workQueue 线程池中的任务队列,通过线程池的execute方法提交的runnable对象会存储在这个参数中。
threadFactory 线程工厂,为线程池提供创建新线程的功能。ThreadFactor是一个接口,它只有一个方法:Thread new Thread(Runnable)
除了以上6个常用参数。
还有一个RejectedExecutionHandler handler,当线程池无法执行新任务时,这可能是由于任务队列已满或者无法成功执行任务,就会调用handler的rejectedExecution。
ThreadPoolExecutor执行任务时遵循的规则:
1.如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
2.如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入到任务队列中排队等待执行。
3.如果在第2点中无法将任务插入到任务队列中,这往往是由于任务队列已满,这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
AsyncTask对THREAD_POOL_EXECUTOR这个线程池进行了配置,配置后的线程池规格如下:
1.核心线程数等于 CPU 核心数+1
2.线程池的最大线程数为CPU 核心数的2倍+1
3.核心线程无超时机制,非核心线程在闲置时的超时时间为1秒;
4.任务队列的容量为128
线程池的分类:
1.FixedThreadPool
newFixedThreadPool方法来创建:
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECOND, new LinkedBlockingQueue<Runnable>());
}
只有核心线程并且这些核心线程没有超时机制,另外任务队列也是没有大小限制的。
使用场景:用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。
2.CachedThreadPool
CachedThreadPool方法来创建:
public static ExecutorService new CachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}
和newFixedThreadPool不同的是,CachedThreadPool的任务队列其实相当一个空集合,这将导致任何任务都会立即被执行。
使用场景:用于执行大量的耗时比较少的任务。当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候的CachedThreadPool实际上没有任务线程的,它几乎是不占用任务系统资源的。
3.ScheduledThreadPool
通过Executor的newScheduledThreadPool方法来创建。它的核心线程数量是固定的,而非核心线程数量是没有限制的,并且当非核心线程闲置时会被立即回收。
public static ScheduledExecutorService new ScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE,0,NANOSECONDS, new DelayedWorkQueue());
}
使用场景:执行定时任务和具有固定周期的重复任务。
4.SingleThreadExecutor
通过Executors的newSingleThreadExecutor方法来创建。
这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。
newSingleThreadExecutor的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。
public static ExecutorService newSingleThreadExecutor(){
return new FinalizeableDelegatedExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}