线程池机制分离了任务的创建和执行。使用线程池执行器,仅需实现Runnable对象,并将该对象交给执行器。执行器会使用线程池中的线程执行,避免额外的创建线程的开销。
线程池执行器起到了维护和管理线程的作用,从而将程序员从繁重的线程管理任务中解放出来。
从JDK1.5开始,Java并发库中引入了Executor框架。该框架包括接口Executor及其接口ExcutorService,以及实现了上面两个接口的类ThreadPoolExecutor。
Executor 接口 :
Executor接口的对象可以接收提交到线程池的Runnable任务。该接口实现了任务的提交和任务的执行分离。
定义:
void execute(Runnble command)
该方法用于异步地(在未来某个时间)执行给定的Runnable对象。
其使用方式如下:
Executor excutor = ...;
executor.execute(new RunnableTask1());
使用executor不用显示地创建线程,也不用显式地调用线程的start()方法。
大多情况下,Executor异步执行提交的Runnable对象,但是,也可以让Executor立即执行提交的任务。例如:
class MyExecutor implements Executor{
public void execute(Runnable r){
r.run(); //直接调用run()方法
}
}
ExecutorService 接口
ExecutorService 接口从父类Executor接口继承。定义如下:
public interface ExecutorService extends Executor
ExecutorService接口提供了关闭线程池的shutdown()方法,关闭后线程池不再接收新的任务。
ThreadPoolExecutor 类
ThreadPoolExecutor类 可以用来创建一个线程池,定义如下:
public class ThreadPoolExecutor extends AbstractExecutorService 它有四个构造方法:
//创建一个线程池执行器对象,corePoolSize 为线程池中的线程数,maxmumPoolSize 为线程池中允许的最大线程数,keepAliveTime 为最长等待时间,unit是keepAliveTime参数的等待时间;workQueue为任务队列。
1)ThreadPoolExecutor( int corePoolSize,int maxmumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>workQueue)
//handler 表示超出线程队列容量时执行的处理程序
2)ThreadPoolExecutor( int corePoolSize,int maxmumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>workQueue,RejectedExecutionHandler handler)
//threadFactory 为创建新的线程时使用的工厂
3)ThreadPoolExecutor( int corePoolSize,int maxmumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>workQueue,ThreadFactory threadFactory)
//
4)ThreadPoolExecutor( int corePoolSize,int maxmumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
ThreadPoolExecutor类的实例可以通过它的构造方法来创建,也可以通过工厂类 Executors的相关方法来创建。
当创建了ThreadPoolExecutor 对象后,就可以将Runnable和Callable对象交给该线程池运行。每一个ThreadPoolExecutor都维护了一些基本信息,例如:已完成的线程数。
Executors 工厂类
工厂类里的静态方法。可以直接调用
例如:
//创建一个线程池,该线程池在需要时创建新的线程,而且会重复利用已经创建的线程,该线程池对于执行那些生命周期较短的异步任务有利于提高性能。
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCacheThreadPool();
ThreadPoolExecutor的使用:
使用线程执行器处理没有返回值的线程
demo 示例 :
//线程工作类
public class Worker implements Runnable{
Worker(String name){
Thread.currentThread().setName(name);
}
public void run(){
System.out.println(Thread.currentThread().getName() + "正在努力完成自己的工作。");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
//线程池类
public class Employer{
//创建线程池执行器
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
public void dispatch(Worker worker){
System.out.println("雇主正在派遣工人到工作岗位上。");
executor.execute(worker);
System.out.println("活动的线程数为:" + executor.getActiveCount() );
System.out.println("线程池的大小为:" + executor.getPoolSize() );
}
public void endWork(){
executor.shutdown();
}
}
//测试启动类
public class Index{
public static void main(String [] args){
int workerNum = Runtime.getRuntime().availableProcessors();
Employer employer = new Employer();
for(int i =0; i<workerNum;i++){
Worker worker = new Worker("工人"+i);
employer.dispatch(worker);
}
employer.endWork();
}
}
运行结果:
雇主正在派遣工人到工作岗位上。
pool-1-thread-1正在努力完成自己的工作。
活动的线程数为:1
线程池的大小为:1
雇主正在派遣工人到工作岗位上。
活动的线程数为:2
线程池的大小为:2
雇主正在派遣工人到工作岗位上。
pool-1-thread-2正在努力完成自己的工作。
活动的线程数为:3
线程池的大小为:3
雇主正在派遣工人到工作岗位上。
pool-1-thread-3正在努力完成自己的工作。
活动的线程数为:4
线程池的大小为:4
雇主正在派遣工人到工作岗位上。
pool-1-thread-4正在努力完成自己的工作。
活动的线程数为:5
线程池的大小为:5
雇主正在派遣工人到工作岗位上。
pool-1-thread-5正在努力完成自己的工作。
活动的线程数为:6
线程池的大小为:6
雇主正在派遣工人到工作岗位上。
pool-1-thread-6正在努力完成自己的工作。
活动的线程数为:7
线程池的大小为:7
pool-1-thread-7正在努力完成自己的工作。
雇主正在派遣工人到工作岗位上。
活动的线程数为:8
线程池的大小为:8
pool-1-thread-8正在努力完成自己的工作。