Android中的线程池

寵の児 提交于 2020-01-15 00:20:53

线程池的好处:

  • 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销
  • 能有效控制线程池的最大并发数,避免大量线程之间因互相抢占系统资源而导致的阻塞现象
  • 能够对线程进行简单的管理,并能提供定时执行以及指定间隔循环执行等功能

Android中的线程池概念来源于Java中Executor.Exeuctor是一个接口,它的真正实现是ThreadPoolExecutor,它提供了一系列参数来配置线程池,通过不同的参数可以创建不同的线程池

ThreadPoolExecutor的构造函数:

public ThreadPoolExecutor ( int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue
                            ThreadFactory threadFactory) {
}

参数说明:

  • corePoolSize:线程池中的核心线程数,默认情况下,核心线程会在线程池中一直存活,即时它们处于闲置状态。如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么他将执行超时策略,由我们指定超时时间,超过这个时间,该线程就会被终止
  • maximumPoolSize:线程池中所能容纳的最大线程数,当活动线程达到这个数值后,后续的新任务将会被阻塞
  • keepAliveTime:非核心线程的超时时长,超过这个时长,非核心线程就会被回收,ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,同样这个属性会作用与核心线程
  • unit:用于指定keepAliveTime的单位
  • workQueue:线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中
  • threadFactory:线程工厂,为线程池提供创建新线程的功能,ThreadFactory是一个接口,它只有一个方法Thread new Thread(Runnable r)

ThradPoolExecutor执行任务大致遵循以下规则:

  1. 如果线程中的线程数量未达到核心线程的数量,那么就会直接启动一个核心线程来处理任务
  2. 如果线程中的线程数量已达到核心线程的数量或者超过这个数量,那么任务会被插入到任务队列中排队等待执行
  3. 如果2中无法插入到任务队列(队列已满),这个时候线程数量未达到规定的线程数,则会启动一个非核心线程处理任务,否则如果超过了最大线程数,则会拒绝执行任务,给调用者一个反馈。

Android中的线程池主要分为四类,分别是FixThreadPool、CacheThreadPool、ScheduleThreadPool以及SingleThreadPool,这四种都是直接或者间接的通过配置ThreadPoolExecutor来实现自己的功能特性。

/*** 创建一种线程数量固定的线程池,线程处于空闲状态,不会被回收 当所有的线程都处于活动状态时,新的任务会处于等待状态,直到有线程可以空出来。* 创建是的线程都是核心线程,且不会被回收,除非线程池关闭。能更快响应外界的请求* 核心的线程没有超时限制,队列也没有大小限制。*/ExecutorService fixedThreadPool=Executors.newFixedThreadPool(int nThreads);
/*** 创建一种线程数量不定的线程池,它只有非核心线程,并且最大线程数为Integer.MAX_VALUE* 当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理任务,否则就会利用空闲的线程来处理任务* 线程池中的线程都有超时的限制,60s,超过60s闲置的线程就会把它回收。比较适合执行大量耗时少的任务/ExecutorService cachedThreadPool=Executors.newCachedThreadPool();
/*** 创建一种线程池,核心线程数固定,非核心线程数量没有限制,非核心线程闲置会被立即回收主要用来处理定时任务和具有固定周期的重复任务。*/ExecutorService scheduledThreadPool=Executors.newScheduledThreadPool(int nThreads);
/*** 创建的线程池中只有一个核心线程,他确保所有的任务都在同一个线程中按顺序执行。 SingleThreadExecutor目的在于统一所有的外界任务到一个线程中,使得在这些任务之间不需要处理线程同步的问题*/ExecutorService singleThreadExecutor=Executors.newSingleThreadExecutor();

 

Android中的HandlerThread和IntentServiceHandlerThread

HandlerThread

HandlerThread是继承Thread的,但是和普通的Thread不同之处在于在它的内部可以创建Handler,这是为什么呢,让我们看下它的run方法

public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

      可以出来出来它内部创建了Looper,创建了消息队列,开启了Loop循环,还有就是普通的Thread内部的run方法一般是用来 执行一个耗时的任务,而它的内部有消息队列,外界需要通过Handler的消息方式来通知它执行一个具体的任务。
IntentService:

IntentService是一种特殊的Service,它继承了Service并且是一个抽象类,因此必须构建它的子类才能使用IntentService,IntentService可用于执行后台任务,当任务执行完成后,会自动停止,从实现上来说IntentService封装了HandlerThread和Handler,下面来通过源码来分析IntentService的onCreate()方法

public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

在它的onCreate()方法中首先创建了一个HandlerThread,然后拿到HandlerThread中的Looper对象
然后创建一个Handler对象通过传入Looper对象,所以可以得出来,这个Handler处理的消息将会运行在HandlerThread线程中。每次启动IntentService它的onStartCommand都会执行,

public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}


public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}

在onStart()方法中将Intent进行了消息的封装,然后mServiceHandler来发送消息

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);
}
}

       然后就会回调handleMessage()方法,紧接着就会调用到我们熟悉的onHandleIntent()方法,大家可以看到这个方法结束,会执行stopSelf(msg.arg1);来停止服务,

public final void stopSelf(int startId) {
        if (mActivityManager == null) {
            return;
        }
        try {
            mActivityManager.stopServiceToken(
                    new ComponentName(this, mClassName), mToken, startId);
        } catch (RemoteException ex) {
        }
    }

 

如果当前后台存在多个任务的时候,只有onHandleIntent执行完最后一个任务时才会停止服务,由于每次执行一个任务就必须启动一次IntentService,又因为它的内部是通过Handler发消息的方式来请求执行任务。Handler中的Looper是按照顺序来执行任务的。所以IntentService也是按照顺序执行后台任务,当有多个后台任务同时存在的时候这些任务会按照外界发起的顺序排队执行。

 

 

 

 

 

 

 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!