Android的线程和线程池

线程分别主线程和子线程。在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>()));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值