Executors类有以下几个方法
5、public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以再指定延迟后执行线程任务,corePoolSize指池中所保存的线程数,即使线程是空闲的也被保存在线程池内。
一、简单使用
1) 建立测试用执行类
public class PoolRunner implements Runnable { private final String name; public PoolRunner(String name) { this.name = name; } @Override public void run() { String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); System.out.println("DateTime:" + dateTime + " Name:" + name + " ThreadName:" + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException ex) { System.out.println(ex.getMessage()); } } }
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); for(int i=0;i<10;i++){ fixedThreadPool.execute(new PoolRunner("name" + i)); } fixedThreadPool.shutdown();执行结果:
DateTime:2015-06-26 10:49:33.530 Name:name3 ThreadName:pool-1-thread-4 DateTime:2015-06-26 10:49:33.530 Name:name0 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:49:33.530 Name:name4 ThreadName:pool-1-thread-5 DateTime:2015-06-26 10:49:33.530 Name:name2 ThreadName:pool-1-thread-3 DateTime:2015-06-26 10:49:33.530 Name:name1 ThreadName:pool-1-thread-2 DateTime:2015-06-26 10:49:34.530 Name:name5 ThreadName:pool-1-thread-2 DateTime:2015-06-26 10:49:34.530 Name:name6 ThreadName:pool-1-thread-4 DateTime:2015-06-26 10:49:34.530 Name:name7 ThreadName:pool-1-thread-5 DateTime:2015-06-26 10:49:34.530 Name:name8 ThreadName:pool-1-thread-3 DateTime:2015-06-26 10:49:34.530 Name:name9 ThreadName:pool-1-thread-1可以看出线程池中总共有5个线程,每个线程执行了2次任务,间隔1秒(由于Run方法中的Sleep)
3)newSingleThreadExecutor
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); for(int i=0;i<10;i++){ singleThreadPool.execute(new PoolRunner("name" + i)); } singleThreadPool.shutdown();执行结果:
DateTime:2015-06-26 10:54:27.937 Name:name0 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:28.937 Name:name1 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:29.937 Name:name2 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:30.937 Name:name3 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:31.937 Name:name4 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:32.937 Name:name5 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:33.937 Name:name6 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:34.937 Name:name7 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:35.937 Name:name8 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:54:36.937 Name:name9 ThreadName:pool-1-thread-1只有一个线程
4)newCachedThreadPool
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for(int i=0;i<10;i++){ cachedThreadPool.execute(new PoolRunner("name" + i)); } cachedThreadPool.shutdown();执行结果:
DateTime:2015-06-26 10:56:28.415 Name:name4 ThreadName:pool-1-thread-5 DateTime:2015-06-26 10:56:28.415 Name:name2 ThreadName:pool-1-thread-3 DateTime:2015-06-26 10:56:28.415 Name:name9 ThreadName:pool-1-thread-10 DateTime:2015-06-26 10:56:28.415 Name:name6 ThreadName:pool-1-thread-7 DateTime:2015-06-26 10:56:28.415 Name:name0 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:56:28.415 Name:name3 ThreadName:pool-1-thread-4 DateTime:2015-06-26 10:56:28.415 Name:name1 ThreadName:pool-1-thread-2 DateTime:2015-06-26 10:56:28.415 Name:name7 ThreadName:pool-1-thread-8 DateTime:2015-06-26 10:56:28.415 Name:name5 ThreadName:pool-1-thread-6 DateTime:2015-06-26 10:56:28.415 Name:name8 ThreadName:pool-1-thread-9总共建立了10个线程
5)newScheduledThreadPool
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); for (int i = 0; i < 10; i++) { String name = "name" + i; String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); System.out.println("ScheduledTime:" + dateTime + " Name:" + name); scheduledThreadPool.schedule(new PoolRunner(name), 1, TimeUnit.SECONDS); } scheduledThreadPool.shutdown();
schedule方法的第二个参数代表延迟多少时间执行,时间单位由最后一个参数决定
执行结果:
ScheduledTime:2015-06-26 10:59:12.576 Name:name0 ScheduledTime:2015-06-26 10:59:12.576 Name:name1 ScheduledTime:2015-06-26 10:59:12.576 Name:name2 ScheduledTime:2015-06-26 10:59:12.576 Name:name3 ScheduledTime:2015-06-26 10:59:12.576 Name:name4 ScheduledTime:2015-06-26 10:59:12.576 Name:name5 ScheduledTime:2015-06-26 10:59:12.576 Name:name6 ScheduledTime:2015-06-26 10:59:12.576 Name:name7 ScheduledTime:2015-06-26 10:59:12.576 Name:name8 ScheduledTime:2015-06-26 10:59:12.576 Name:name9 DateTime:2015-06-26 10:59:13.586 Name:name0 ThreadName:pool-1-thread-4 DateTime:2015-06-26 10:59:13.586 Name:name3 ThreadName:pool-1-thread-3 DateTime:2015-06-26 10:59:13.586 Name:name2 ThreadName:pool-1-thread-2 DateTime:2015-06-26 10:59:13.586 Name:name1 ThreadName:pool-1-thread-5 DateTime:2015-06-26 10:59:13.586 Name:name4 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:59:14.586 Name:name5 ThreadName:pool-1-thread-1 DateTime:2015-06-26 10:59:14.586 Name:name7 ThreadName:pool-1-thread-3 DateTime:2015-06-26 10:59:14.586 Name:name6 ThreadName:pool-1-thread-5 DateTime:2015-06-26 10:59:14.586 Name:name8 ThreadName:pool-1-thread-2 DateTime:2015-06-26 10:59:14.586 Name:name9 ThreadName:pool-1-thread-4创建了保持5个线程的线程池,线程执行延迟1秒执行
ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); for (int i = 0; i < 10; i++) { String name = "name" + i; String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); System.out.println("ScheduledTime:" + dateTime + " Name:" + name); singleScheduledThreadPool.schedule(new PoolRunner(name), 1, TimeUnit.SECONDS); } singleScheduledThreadPool.shutdown();执行结果:
ScheduledTime:2015-06-26 11:02:06.652 Name:name0 ScheduledTime:2015-06-26 11:02:06.662 Name:name1 ScheduledTime:2015-06-26 11:02:06.662 Name:name2 ScheduledTime:2015-06-26 11:02:06.662 Name:name3 ScheduledTime:2015-06-26 11:02:06.662 Name:name4 ScheduledTime:2015-06-26 11:02:06.662 Name:name5 ScheduledTime:2015-06-26 11:02:06.662 Name:name6 ScheduledTime:2015-06-26 11:02:06.662 Name:name7 ScheduledTime:2015-06-26 11:02:06.662 Name:name8 ScheduledTime:2015-06-26 11:02:06.662 Name:name9 DateTime:2015-06-26 11:02:07.672 Name:name0 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:08.674 Name:name1 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:09.674 Name:name2 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:10.674 Name:name3 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:11.678 Name:name4 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:12.678 Name:name5 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:13.679 Name:name6 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:14.686 Name:name7 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:15.686 Name:name8 ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:02:16.688 Name:name9 ThreadName:pool-1-thread-1延迟1秒执行,但是只有一个单独的线程
二、ThreadFactory
所以线程池的初始化方法都可以自定义ThreadFactory
这样就可以在初始化线程的时候做一些设定,比如使用setUncaughtExceptionHandler对异常进行处理、写入Log。
实现一个更改线程名的ThreadFactory作为测试:
public class ErrorRunner implements Runnable { @Override public void run() { throw new RuntimeException("Thread Exception Test."); } } public class MyThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl()); return thread; } private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + " error:" + e.getMessage()); } } }创建线程池:
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(new MyThreadFactory()); singleThreadPool.execute(new ErrorRunner()); singleThreadPool.shutdown();执行结果:
run: Thread-0 error:Thread Exception Test.
scheduleAtFixedRate严格按照指定的时间间隔执行任务。如果任务的执行时间大于指定的时间间隔,则在上一个任务结束后直接启动下一个任务
scheduleWithFixedDelay在上一个任务结束以后,再等待指定的间隔时间,才会启动下一个任务
示例:
2)scheduleAtFixedRate
ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); String name = "LoopTest"; String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); System.out.println("ScheduledTime:" + dateTime + " Name:" + name); singleScheduledThreadPool.scheduleAtFixedRate(new PoolRunner(name), 1, 2, TimeUnit.SECONDS); Thread.sleep(10000); System.out.println("ShutDown!"); singleScheduledThreadPool.shutdown();scheduleAtFixedRate第三个参数代表设定的时间间隔
注意上面建立的PoolRunner类的Run方法中会Sleep 1秒
执行结果:
run: ScheduledTime:2015-06-26 11:49:45.752 Name:LoopTest DateTime:2015-06-26 11:49:46.744 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:48.767 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:50.767 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:52.767 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:54.767 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:56.767 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:49:58.768 Name:LoopTest ThreadName:pool-1-thread-1 ShutDown!每次执行间隔2秒钟
将PoolRunner类的Run方法中会Sleep改为3秒后再次执行
执行结果:
run: ScheduledTime:2015-06-26 11:52:32.625 Name:LoopTest DateTime:2015-06-26 11:52:33.635 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:52:36.636 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:52:39.641 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:52:42.647 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:52:45.647 Name:LoopTest ThreadName:pool-1-thread-1 ShutDown!执行间隔变为3秒
3)scheduleWithFixedDelay
将PoolRunner类的Run方法中会Sleep改1秒后执行如下代码
ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); String name = "LoopTest"; String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); System.out.println("ScheduledTime:" + dateTime + " Name:" + name); singleScheduledThreadPool.scheduleWithFixedDelay(new PoolRunner(name), 1, 2, TimeUnit.SECONDS); Thread.sleep(10000); System.out.println("ShutDown!"); singleScheduledThreadPool.shutdown();执行结果:
run: ScheduledTime:2015-06-26 11:54:50.718 Name:LoopTest DateTime:2015-06-26 11:54:51.726 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:54:54.733 Name:LoopTest ThreadName:pool-1-thread-1 DateTime:2015-06-26 11:54:57.743 Name:LoopTest ThreadName:pool-1-thread-1 ShutDown!
可以看到执行间隔依然为3秒,因为scheduleWithFixedDelay方法会在每次任务执行结束(耗时1秒)后再等待2秒,才会启动下一次任务
4. submit 方法
Callable中的call()方法类似Runnable的run()方法。但是call()方法有返回值,run()方法没有。
使用submit方法,就可以从方法返回的Future对象中取得返回值的内容。
示例:
public class PoolCaller implements Callable<String> { private final String name; public PoolCaller(String name) { this.name = name; } @Override public String call() throws Exception { String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); String result = "DateTime:" + dateTime + " Name:" + name + " ThreadName:" + Thread.currentThread().getName(); Thread.sleep(1000); return result; } }
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); Future<String> submit = singleThreadPool.submit(new PoolCaller("SubmitTest")); System.out.println(System.currentTimeMillis()); System.out.println(submit.get()); System.out.println(System.currentTimeMillis()); singleThreadPool.shutdown();执行结果:
run: 1435297292530 DateTime:2015-06-26 01:41:32.560 Name:SubmitTest ThreadName:pool-1-thread-1 1435297293560可以看出来,Future的get方法会等待任务执行完成,然后返回call方法的返回值。
Future<?> submit(Runnable task)返回的Future对象调用get时会返回null
<T> Future<T> submit(Runnable task, T result)方法则会把传入的result的对象再返回出来
5. invokeAll方法
当要执行多个Callable的时候则可以使用invokeAll方法,它会在所有任务执行完以后返回一个Future的List
示例:
public class PoolCaller implements Callable<String> { private final String name; public PoolCaller(String name) { this.name = name; } @Override public String call() throws Exception { String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()); String result = "DateTime:" + dateTime + " Name:" + name + " ThreadName:" + Thread.currentThread().getName(); System.out.println(result); Thread.sleep(1000); return name + " is done!"; } }
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); List<PoolCaller> list = new ArrayList(){{ add(new PoolCaller("invokeAll-1")); add(new PoolCaller("invokeAll-2")); }}; List<Future<String>> result = singleThreadPool.invokeAll(list); for(Future<String> future: result){ System.out.println(future.get()); } singleThreadPool.shutdown();执行结果:
run: DateTime:2015-06-26 02:08:46.309 Name:invokeAll-1 ThreadName:pool-1-thread-1 DateTime:2015-06-26 02:08:47.309 Name:invokeAll-2 ThreadName:pool-1-thread-1 invokeAll-1 is done! invokeAll-2 is done!
invokeAny方法则会任意执行传入的一组task中的任意一个。