针对android中的多线程请求,本文主要介绍 android中线程池的基本使用。
1:线程池的分类
FixedThreadPool:它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭,当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。该线程池中只有核心线程,并且这些核心线程不会被回收,这意味着它能够更加快速的响应外界的请求。
CachedThreadPool: 该线程池中线程数量不固定,并且内部只有非核心线程,其线程的最大值为 Integer.MAX_VALUE。所以可以认为该线程池中的线程数量可以任意大。该线程池的特定是当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新的任务,否则就会利用空闲的线程来处理新的任务。该线程池中的空闲线程都有超时机制,这个超时时长为 60s ,超过60s 空闲线程就会被回收。
ScheduledThreadPool: 该线程池中包含核心线程以及非核心线程,核心线程数量是固定的,而非核心线程数量是没有限制的,并且当非核心线程闲置时会被立即回收。
SingleThreadExecutor:该线程池是一个单例线程,其内部只有一个核心线程。
2:线程池的基本使用
FixedThreadPool:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4)
fixedThreadPool.execute(runnable)
CachedThreadPool:
ExecutorService cacheThreadPool = Executors.newCachedThreadPool()
cacheThreadPool.execute(runnable)
ScheduledThreadPool:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4)
scheduledThreadPool.schedule(runnable3, 2000, TimeUnit.MILLISECONDS)
SingleThreadExecutor:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor()
singleThreadExecutor.execute(runnable)
3: 线程池构造解析
android中线程池概念来源于java中的Executor,而Executor通过源码我们可以看出是一个接口;
public interface Executor {
void execute(Runnable command);
}
内部只包含一个抽象方法 execute(….);
同时android中 重新定义了ExecutorService接口去继承上述接口;
public interface ExecutorService extends Executor{}
而 ExecutorService 接口的实现类是:
public abstract class AbstractExecutorService implements ExecutorService{}
抽象类AbstractExecutorService 的具体实现是:
public class ThreadPoolExecutor extends AbstractExecutorService{}
通过上述关系可以看到线程池的真正实现为ThreadPoolExecutor,在ThreadPoolExecutor 中提供了一系列的参数来创建不同的线程池。
下面我们来看ThreadPoolExecutor的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}
内部参数:
corePoolSize:线程的核心线程数;
maximumPoolSize:线程池所能容纳的最大线程数:
keepAliveTime:非核心线程闲置时的超时市场,超过这个时长非核心线程就会被回收
unit:用于指定keepAliveTime 的单位
workQueue:线程池中的任务队列
threadFactory:线程工厂,为线程池提供创建新线程的功能
handler:当线程池无法执行新的任务时,会调用handler的rejectedEcexutor方法来通知调用者。该参数不常用,可以忽略。
通过源码我们可以看到google是通过工厂方式去创建各种线程池,具体源码我们可以通过
public class Executors{}
该类可以看到内部通过各种方法去获取不同的线程池。
下面我们根据Executors 中各个方法去看各个线程池是如何实现的。
FixedThreadPool:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
FixedThreadPool 通过调用 ThreadPoolExecutor构造函数 可以看出实质上是通过外部设置了 核心线程数,以及非核心线程数。
CachedThreadPool:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
CachedThreadPool 内部可以看出实质上 核心线程数为0 ,而非核心线程数为Int最大值
SingleThreadExecutor:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
SingleThreadExecutor 可以看出实质上是核心线程数以及非核心线程数均为1;
ScheduledThreadPool:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
....
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
....
}
ScheduledThreadPool 可以看出核心线程数是通过外部设置,而非核心线程数实质是int的最大值。
4 : 线程池的基本执行流程
1:如果线程池中核心线程未达到上限那么,则会直接启动一个核心线程去执行任务;
2:如果核心线程达到上限,那么会将任务放到任务队列中,等待执行,
3:如果任务无法插入到任务队列中,则会开启一个非核心线程去执行任务,
4:如果线程池中的线程已经达到线程数量的上限,则将不会去执行任务,ThreadPoolExecutor将会调用RejectedExecutionHandler的rejectedExecution方法通知调用者。
以下通过图示来说明:
