在jdk1.5之前创建执行线程主要通过Thread类和Runable接口来实现(本质都是通过Thread来启动),线程的频繁创建在高并时是非常消耗资源的,所有jdk1.5之前没有可靠的线程机制来处理这些问题。在jdk1.5后推出了java.util.concurrent包,该包提供了通过线程池来管理线程的机制,线程池的作用主要就是限制系统中使用线程的数量以及更好的使用线程,减少不必要的开销。线程池通过配置线程数量,数量满了后,其他线程需要排队等候,当一个任务执行完毕后,就从队列中取一个新任务运行,如果没有新任务,那么这个线程将等待。如果来了一个新任务,但是没有空闲线程的话,那么把任务加入到等待队列中。
1、Executor接口
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the Executor implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution.
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
Executor为顶级接口,用于执行已提交的 Runnable 任务的对象。创建一个线程通常使用Executor,而不是显式地创建线程如new Thread(new(RunnableTask())).start()。
2、ExecutorService接口(线程池接口)
public interface ExecutorService extends Executor {
void shutdown();//关闭线程池,在终止前允许执行以前提交的任务
List shutdownNow();//关闭线程池,并试图停止当前正在执行的任务
boolean isShutdown();//当调用shutdown()方法后返回为true。
boolean isTerminated();//若关闭后所有任务都已完成,则返回true
Future submit(Callable task); //提交一个有返回值的任务
Future submit(Runnable task, T result);
Future> submit(Runnable task);// 提交一个 Runnable 任务
//...
}
ExecutorService接口在Executor的基础上提供了对任务执行的生命周期的管理。
3、ThreadPoolExecutor类
ThreadPoolExecutor是ExecutorService的一个重要实现类,它实现了基于线程池的任务执行框架。
public class ThreadPoolExecutor extends AbstractExecutorService {
// ...
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
// ...
}
上面代码是ThreadPoolExecutor的构造器,具体参数说明如下:
1. corePoolSize -- 线程池大小
2. maximumPoolSize -- 线程池最大数量
3. keepAliveTime -- 线程从队列中获取任务的超时时间,如果线程空闲超过这个时间就会终止。
4. unit -- 时间单位
5. workQueue -- 工作队列(阻塞),用于存放提交的任务
6. threadFactory -- 通过线程工厂创建新的线程,可以改变线程的名称、线程组、优先级、守护进程状态等
7. handler -- 任务被拒绝的hook(钩子)
demo:
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
// ThreadFactory 作用
ThreadPoolExecutor tpe =new ThreadPoolExecutor(5, 50, 10, TimeUnit.SECONDS, new LinkedBlockingQueue(),new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("修改线程名称...");
return thread;
}
});
tpe.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
}
下面程序运行结果:
构造参数corePoolSize,maximumPoolSize,workQueue之间关系说明:
public class ThreadPoolExecutor extends AbstractExecutorService {
// ...
private static int workerCountOf(int c) { return c & CAPACITY; }
private final BlockingQueue workQueue;//任务队列
private volatile RejectedExecutionHandler handler;
private volatile int corePoolSize;//线程池大小
private volatile int maximumPoolSize;
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 活动的线程数 < corePoolSize
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 活动线程数 >= corePoolSize
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
// ...
}
1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
4、Executors类
Executors类提供了一些列静态的方法用于创建线程池,这些静态方法本质上还是调用new ThreadPoolExecutor()来产生ExecutorService,和直接调用new ThreadPoolExecutor()没有任何区别,下面是简单的说明:
(1)创建一个单线程的线程池
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();//这个线程池只有一个线程在工作。
(2)创建一个固定线程数量的线程池
public class ExecutorsTest {
public static void main(String[] args) {
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 6; i++) {
newFixedThreadPool.execute(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name);
}
});
}
}
}
以上代码等价于:
public class ExecutorsTest {
public static void main(String[] args) {
ExecutorService newFixedThreadPool = new ThreadPoolExecutor(5, 5,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
for (int i = 0; i < 6; i++) {
newFixedThreadPool.execute(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name);
}
});
}
}
}
(3)创建一个可缓存的线程池
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
以上代码等价于:
ExecutorService newCachedThreadPool = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());