Executors类有以下几个方法
1、public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。
2、public static ExecutorService newSingleThreadExecutor():创建一个只有单线程的线程池,它相当于newFixedThreadPool方法是传入的参数为1
3、public static ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。
4、public static ScheduledExecutorService newSingleThreadScheduledExecutor:创建只有一条线程的线程池,他可以在指定延迟后执行线程任务
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秒执行6)newSingleThreadScheduledExecutor
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.三、定时计划循环执行
1)scheduleAtFixedRate和scheduleWithFixedDelay的区别
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!另外invokeAll方法还有一个设置timout的重载,如果超过时间则会将已经完成的task返回,未完成的取消。
invokeAny方法则会任意执行传入的一组task中的任意一个。
170万+

被折叠的 条评论
为什么被折叠?



