1. 线程池使用
使用new Thread()创建线程存在的问题:
频繁创建线程,执行完后又被回收,导致频繁GC
多线程缺乏统一管理,各线程之间互相竞争,降低程序运行效率
无法有效控制线程的执行、取消等。
使用线程池的优点:
重用线程池中的线程,避免线程的创建和销毁带来的性能开销
有效控制线程池的最大并发数,避免大量线程之间因胡抢占资源导致阻塞现象
对线程进行简单管理,并提供定时执行,指定间隔循环执行等
Android中的线程池源于Java中的Executor,其本身是一个接口,真正的实现类是ThreadPoolExecutor。
1.1 ThreadPoolExecutor
ThreadPoolExecutor有四个重载的构造方法,介绍以下参数最多的构造器如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数含义:
corePoolSize: 线程池中核心线程的数量,默认情况会在线程池中一直存活。可以通过allowCoreThreadTimeOut和keepAliveTime设置核心线程闲置超时终止。
maximumPoolSize: 线程池中最大线程数量,活动线程数达到这个数,后续新任务会阻塞
keepAliveTime: 非核心线程的超时时长
unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等(TimeUnit.MILLISECONDS\TimeUnit.SECONDS........)
workQueue 线程池中的任务队列, 通过线程池execute方法提交的Runnable对象会存储在这个参数中
threadFactory 为线程池提供创建新线程的功能, 是一个接口,只有一个方法:Thread newThead(Runnable r)
handler 拒绝策略 当线程无法执行新任务时,默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException(拒绝策略有:CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy)
运行规则:
运行线程,线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行
运行线程,核心线程数已满且workQueue未满,新线程放入workQueue中等待执行
运行线程,核心线程已满、workQueue已满且未超过非核心线程数,开启一个非核心线程来执行任务
运行线程,三者都满,拒绝执行该任务
示例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
poolExecutor = new ThreadPoolExecutor(3, 5,
1, TimeUnit.SECONDS, new LinkedBlockingDeque(128));
}
public void btnClick(View view) {
for (int i = 0; i < 30; i++) {
final int finalI = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
Log.d("google_lenve_fb", "run: " + finalI);
}
};
poolExecutor.execute(runnable);
}
}
线程池中线程相关参数该怎么配置呢?可以参考AsyncTask。其源码如下:
public abstract class AsyncTask {
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
....
....
}
从上述代码我们可以知道:
核心线程数为手机CPU数 + 1(cpu数量获取方式Runtime.getRuntime().availableProcessors())
线程池线程数为手机CPU数*2 + 1
线程队列大小:128
如果要使用线程池,可以参考这个再根据实际配置。
1.2 线程池分类
线程池可以分为四类:FixedThreadPool、CachedThreadPool、ScheduledThreadPool、以及SingleThreadExecutor
FixedThreadPool
是一个核心线程数量固定的线程池。通过Executors的newFixedThreadPool创建。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
其源码为:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
FixedThreadPool中没有非核心线程,所有的线程都是核心线程,它们不会被回收,除非线程池被关闭了。核心线程没有超时机制。
CachedThreadPool
通过Executor的newCachedThreadPool,是一种线程数量不定的线程池,没有核心线程,最大线程数Integer.MAX_VALUE,有线程超时机制,超时时间60秒。使用SynchronousQueue作为线程队列,适合执行大量的耗时较少任务。
源码如下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
ScheduledThreadPool
通过Executor的newScheduledThreadPool创建,核心线程数固定,非核心线程数没有限制。一旦非核心线程闲置被立即回收。适合执行定时任务和具有固定周期的重复任务。
public static ScheduledExecutorService new ScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
SingleThreadPool
通过Executor的newSingleThreadPool创建。只有一个核心线程
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
1.3 线程池常用功能
1.shutDown() 关闭线程池,不影响已经提交的任务
2.shutDownNow() 关闭线程池,并尝试去终止正在执行的线程
3.allowCoreThreadTimeOut(boolean value) 允许核心线程闲置超时时被回收
4.submit 一般情况下我们使用execute来提交任务,但是有时候可能也会用到submit,使用submit的好处是submit有返回值