Java Executor framework是围绕Executor接口和它的子接口ExecutorService和ThreadPoolExecutor类实现了上述两接口。此机制将创建和执行任务分离,使用executor,仅需要实现Runnable对象,发送给executor。executor负责执行,初始化和运行必要的线程。
executor framework的另外一个特点是Callalbe接口:它的主方法时call方法,且返回一个结果。当发送callalbe给executor时,会得到一个实现了Future接口的对象,它可以控制callalbe对象的状态和结果
创建线程执行器
ThreadPoolExecutor类有四个构造器,但是由于其复杂性,Java并发API提供了静态类Executors来构建executors和其他相关对象。可以直接使用ThreadPoolExecutor。
/*Executors的实例方法返回的是ExecutorService
*缓存线程并重复利用,避免了线程创建,
若缓存线程过多,导致系统负载加重
*/
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
getPoolSize()//线程池中实际线程数
getActiveCount()//线程池中正在执行task的线程数
getCompletedTaskCount()//线程池已经处理的task数
/*关闭线程池,必须显示执行
*不会执行被挂起的任务,当前正在执行的任务会继续执行
最终返回被挂起的任务列表
*/
shutdownNow()
/*
调用shutdown()或shutdownNow()方法,
且执行器完成了shut down的过程,返回true
*/
isTerminated()
/**
如果调用shutdown()或shutdownNow(),返回true
*/
isShutdown()
/*
此方法会阻塞调用线程,直到超时或执行器结束
*/
awaitTermination(long timeout, TimeUnit unit)
执行器中执行返回结果的任务
Callable:使用泛型的接口,必须指定返回的结果类型
Future:此接口有一些方法获得Callable对象生成的结果并管理其状态
Future:此接口有一些方法获得Callable对象生成的结果并管理其状态
public class FactorialCalculator implements Callable<Integer> {
private Integer number;
public FactorialCalculator(Integer number){
this.number=number;
}
@Override
public Integer call() throws Exception {
int result = 1;
if ((num==0)||(num==1)) {
result=1;
} else {
for (int i=2; i<=number; i++) {
result*=i;
TimeUnit.MILLISECONDS.sleep(20);
}
}
return result;
}
}
public class Main {
public static void main(String[] args) {
ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(2);
List<Future<Integer>> resultList=new ArrayList<>();
Random random=new Random();
for (int i=0; i<10; i++){
Integer number= random.nextInt(10);
FactorialCalculator calculator=new FactorialCalculator(number);
Future<Integer> result=executor.submit(calculator);//返回为Future接口
resultList.add(result);
}
do {
for (int i=0; i<resultList.size(); i++) {
Future<Integer> result=resultList.get(i);
}
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (executor.getCompletedTaskCount()<resultList.size());
for (int i=0; i<resultList.size(); i++) {
Future<Integer> result=resultList.get(i);
Integer number=null;
try {
number=result.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
}
执行多个任务,处理第一个结果
List<TaskValidator> taskList=new ArrayList<>();
taskList.add(ldapTask);
taskList.add(dbTask);
ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();
try {
result = executor.invokeAny(taskList);
System.out.printf("Main: Result: %s\n",result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
invokeAny()//接受一组任务列表,并行发起,返回第一个结束且没有抛出异常的结果
运行多个task,处理所有结果
List<Future<Result>>resultList = executor.invokeAll(taskList);
executor.shutdown();
//执行所有的task,当所有的任务在超时之前都执行完成后返回他们的结果
invokeAll(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit)
executors中延迟运行task
ScheduledThreadPoolExecutor executor=(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);
executor.schedule(task,i+1 , TimeUnit.SECONDS);
executor.shutdown();//
executor.awaitTermination(1, TimeUnit.DAYS);
/*
默认情况下,所有那些等待delay挂起的任务将被执行,尽管
执行器finalization,可以通过以下方法传入false
被挂起的task不会被执行
*/
setExecuteExistingDelayedTasksAfterShutdownPolicy()
executors中周期运行task
/*
第一参数:延迟时间
第二参数:周期
第三参数:时间单位
*/
ScheduledFuture<?> result=executor.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);
scheduledFuture.getDelay()//到下次task执行时间
setContinueExistingPeriodicTasksAfterShutdownPolicy()//同上节方法,修改shutdown()默认行为
取消executors中的task
使用Future的cancel()方法,如果task已经完成或已经被取消或其他原因不能被取消,返回false,task不会被取消。如果task在executor中等待获取线程,task被取消且不会开始执行。如果task已经运行,取决于cancel的参数,若位true,且task正在执行,将会被取消。若为false,task正在执行,不会被取消。控制executor中正在finishing的task
FutureTask类提供了done()方法,允许task执行完成后执行一些代码,用来做些post-process操作。此方法在task的结果被设置且状态变更为isDone状态后执行。
ExecutableTask executableTask=new ExecutableTask("Task ");//ExecutableTask实现Callalbe接口
resultTasks=new ResultTask(executableTask);//用FutureTask包装Callable对象
executor.submit(resultTasks);
在executor中分离正在发起的task,处理它们的结果
CompletionService类有一个方法发送task给一个executor,和另外一个方法为在下一个task中获取Future对象。此行为的优点共享CompletionService对象,发送task给executor,其他task能处理结果。public class ReportGenerator implements Callable<String> {
private String sender;
private String title;
public ReportGenerator(String sender, String title){
this.sender=sender;
this.title=title;
}
@Override
public String call() throws Exception {
try {
Long duration=(long)(Math.random()*10);
System.out.printf("%s_%s: ReportGenerator: Generating a
report during %d seconds\n",this.sender,this.title,duration);
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
String ret=sender+": "+title;
return ret;
}
}
public class ReportRequest implements Runnable {
private String name;
private CompletionService<String> service;
public ReportRequest(String name, CompletionService<String> service){
this.name=name;
this.service=service;
}
@Override
public void run() {
ReportGenerator reportGenerator=new ReportGenerator(name,"Report");
service.submit(reportGenerator);//生成消息,并置入completeservice的队列中
}
public class ReportProcessor implements Runnable {
private CompletionService<String> service;
private boolean end;
public ReportProcessor (CompletionService<String> service){
this.service=service;
end=false;
}
public void run() {
while (!end){
try {
Future<String> result=service.poll(20, TimeUnit.SECONDS);//从service队列中取得前task的结果
if (result!=null) {
String report=result.get();
System.out.printf("ReportReceiver: Report Received: %s\n",report);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
System.out.printf("ReportSender: End\n");
}
public void setEnd(boolean end) {
this.end = end;
}
}
ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();
CompletionService<String> service=new ExecutorCompletionService<>(executor);
ReportRequest faceRequest=new ReportRequest("Face", service);
ReportRequest onlineRequest=new ReportRequest("Online", service);
Thread faceThread=new Thread(faceRequest);
Thread onlineThread=new Thread(onlineRequest);
ReportProcessor processor=new ReportProcessor(service);
Thread senderThread=new Thread(processor);
faceThread.start();
onlineThread.start();
senderThread.start();
控制被executor拒绝的task
当提供调用shutdown()后,再提交task给executor时候,此task会被rejected。RejectedExecutionHandler提供了一种机制处理被rejected的task。
public class RejectedTaskController implements
RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.printf("RejectedTaskController: The task %s has
been rejected\n",r.toString());
System.out.printf("RejectedTaskController: %s\n",executor.
toString());
System.out.printf("RejectedTaskController: Terminating:
%s\n",executor.isTerminating());
System.out.printf("RejectedTaksController: Terminated:
%s\n",executor.isTerminated());
}
}
executor.setRejectedExecutionHandler(controller);