当我们要有很多子任务需要执行的时候,我们不可能每个子任务开一个线程去执行,这样会严重影响程序的性能,这时候就可以用线程池了。线程池可以重用其中的线程,避免线程反复创建和销毁带来的性能开销,而且可以有效控制并发数。
Java线程池中的核心类是ThreadPoolExecutor,该类Oracle官网API文档传送门:ThreadPoolExecutor。它有四个构造方法,我们来看下那个参数最多的,其它的也就知道了:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
参数的含义文档里都有,如下(我是从源码里贴过来的,感觉源码里排版更好点。。。):
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
下面自己结合自己的理解说明下。一般情况下,一个Runnable提交到线程池,如果此时corePoolSize没达到,直接执行,否者放到workQueue(这是个BlockingQueue),如果workQueue满了,则再新建线程执行,如果maximumPoolSize再超了的话,就该handler上了。
Java中有四种我们常用的配置好的线程池,通过Executors中的静态方法,我们可以直接创建它们,下面是源码中它们的配置(当然不只一种new的方法,有重载,具体看源码):
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newSingleThreadExecutor和newScheduledThreadPool可以自己去源码中看,ThreadPoolExecutor中参数含义知道,阻塞队列的特性知道的话,应该OK的。
下面是一个简单的使用:
package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test5 {
public static void main(String[] args) {
new Test5().Method();
}
public void Method() {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0;i < 9;i++) {
executorService.execute(new MyThread(i));
}
executorService.shutdown();
}
class MyThread implements Runnable {
private int mThreadID;
public MyThread(int mThreadID) {
this.mThreadID = mThreadID;
}
@Override
public void run() {
int num = 5;
while (num > 0) {
System.out.print(mThreadID + " ");
num--;
}
}
}
}
某次的运行结果:
1 0 2 0 1 0 2 0 1 0 2 2 2 3 1 3 4 3 1 3 4 3 5 4 4 5 5 6 5 4 5 6 8 7 8 6 8 7 8 6 8 7 7 7 6
根据结果大体可以看出来最多只允许3个线程同时跑。。。
下面是我在Android中对线程池的一个简单使用:线程池配合RecyclerView实现从网上加载大量图片显示