接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且可以让任务在后台执行。在下面的例子中可以发现线程被循环创建,但是启动线程却不是连续的,而是由ExecutorService决定的。
ExecutorService是一个接口,继承了Executor。而Executor亦是一个接口,该接口只包含了一个方法:void execute(Runnable command);
,该方法接收一个 Runable 实例,它用来执行一个任务,任务即一个实现了 Runnable 接口的类。
创建ExecutorService:
Executors 提供了一系列工厂方法用于创先线程池,返回的线程池都实现了 ExecutorService 接口。
-
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。 -
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。 -
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。 -
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持延迟及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutorService 使用方法:
这里有几种不同的方式让你将任务委托给壹個 ExecutorService。
-
execute(Runnable)
executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } });
Future submit(Runnable)
同样接收壹個 Runnable 的实现作为参数,但是会返回一個 Future 对象。这個 Future 对象可以用于判断 Runnable 是否结束执行。
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
//如果任务结束执行则返回 null
System.out.println("future.get()=" + future.get());Future submit(Callable)
Callable 的 call() 方法可以返回壹個结果。Callable 的返回值可以从方法 submit(Callable) 返回的 Future 对象中获取。
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());T invokeAny(Collection<Callable>)
任务集合中,任何一个任务完成就返回。
接收Callable 对象的集合作为参数。调用该方法不会返回 Future 对象,而是返回集合中某一個 Callable 对象的结果。
无法保证调用之后返回的结果是哪個 Callable。
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();List<Future> invokeAll(Collection<Callable>)
同步的方法,执行所有的任务列表,当所有任务都执行完成后,返回Future列表。
执行 Runnable 任务:
通过 Executors 的以上四个静态工厂方法获得 ExecutorService 实例,而后调用该实例的 execute(Runnable command)方法即可。一旦 Runnable 任务传递到 execute()方法,该方法便会自动在一个线程上执行。下面是 Executor 执行 Runnable 任务的示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCachedThreadPool{
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
// ExecutorService executorService = Executors.newFixedThreadPool(5);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++){
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************");
}
executorService.shutdown();
}
}
class TestRunnable implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName() + "线程被调用了。");
}
}
执行结果如下:
从结果中可以看出,pool-1-thread-1 和 pool-1-thread-2 均被调用了两次,这是随机的,execute 会首先在线程池中选择一个已有空闲线程来执行任务,如果线程池中没有空闲线程,它便会创建一个新的线程来执行任务。
ExecuteService 服务的关闭:
当使用 ExecutorService 完毕之后,我们应该关闭它。 例如:你的程序通过 main() 方法启动,并且主线程退出了你的程序,如果你还有壹個活动的 ExecutorService 存在于你的程序中,那么程序将会继续保持运行状态。存在于 ExecutorService 中的活动线程会阻止Java虚拟机关闭。
为了关闭在 ExecutorService 中的线程,你需要调用 ***shutdown() 方法。executorService.shutdown();
ExecutorService 并不会马上关闭,而是不再接收新的任务,壹但所有的线程结束执行当前任务,ExecutorServie 才会真的关闭。所有在调用 shutdown() 方法之前提交到 ExecutorService 的任务都会执行。
如果你希望立即关闭 ExecutorService,你可以调用 shutdownNow() ***方法。executorService.shutdownNow();
这個方法会尝试马上关闭所有正在执行的任务,并且跳过所有已经提交但是还没有运行的任务。但是对于正在执行的任务,是否能够成功关闭它是无法保证的。
awaitTermination方法,方法调用会被阻塞,直到所有任务执行完毕并且shutdown请求被调用,或者参数中定义的timeout时间到达,或者当前线程被打断,这几种情况任意一个发生了就会导致该方法的执行。接收timeout和TimeUnit两个参数,用于设定超时时间及单位。当等待超过设定时间时,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。(若超时未关闭,程序也继续往下进行。传入Long.MAX_VALUE, TimeUnit.DAYS
参数,可确保子进程完成。)一般情况下会和shutdown方法组合使用。
// 关闭启动线程
service.shutdown();
// 等待子线程结束,再继续执行下面的代码
service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); //这里表示近似永远等待
//service.awaitTermination(1, TimeUnit.MINUTES);//等待一分钟
//service.awaitTermination(2, TimeUnit.SECONDS);//两秒钟
System.out.println("all thread complete");
还有 service.isTerminated()
,service.isTerminating()
,service.isShutdown()
等方法。
参考:
http://wiki.jikexueyuan.com/project/java-concurrency/executor.html
http://blog.csdn.net/bairrfhoinn/article/details/16848785
http://shift-alt-ctrl.iteye.com/blog/1841088