首先在功能上几乎没有什么区别
1.后者可以更好复用,比如
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
Callable<Integer> a = () -> {
int count = 5;
while (--count > 0) {
System.out.println("Callable");
Thread.sleep(1000L);
}
return 10;
};
Runnable b = () -> {
int count = 7;
while (--count > 0) {
System.out.println("Runnable");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
service.submit(a);
service.submit(b);
}
这里我创建一个callable, 一个runable,如果runnable依赖callable的结果, 那么就可以先提交a,在提交b.
Callable
Callable
Callable
Callable
Runnable
Runnable
Runnable
Runnable
Runnable
Runnable
从上面的结果可以看出,任务的执行是有顺序的,那么顺序是从哪里的来的呢?
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
原因是看上面的代码,虽然他是只有一个线程的线程池,但是第二个任务submit之后,会被放到队列中等待执行,
不会去真的竞争,而是执行完一个之后,才可能执行下一个,这样就不用执行a那new一个线程,执行b又new一个线程了。 这样的话,单纯的new Thread()优秀多了。
2.new Thread() 方法会直接抛出异常,在System.err中可以看到,但是后者是会在内部处理发生的异常,正常情况下是看不到的。
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
Callable<Integer> a = () -> {
int count = 5;
while (--count > 0) {
System.out.println("Callable");
Thread.sleep(1000L);
throw new IllegalArgumentException("throw !");
}
return 10;
};
Runnable b = () -> {
int count = 7;
while (--count > 0) {
System.out.println("Runnable");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
service.submit(a);
service.submit(b);
}
修改开始的代码,在a上加上一行抛出异常的代码。结果如下
Callable
Runnable
Runnable
Runnable
Runnable
Runnable
Runnable
结果显而易见,异常在第一次就发生,随后a停止运行,开始执行b,异常被内部处理了,
那么问题来,如何才能看见线程池内部出现的异常呢?a是Callable,理论上a执行完是可以获得执行的结果的,所以试着去获取ade执行的结果
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService service = Executors.newSingleThreadExecutor();
Callable<Integer> a = () -> {
int count = 5;
while (--count > 0) {
System.out.println("Callable");
Thread.sleep(1000L);
throw new IllegalArgumentException("throw !");
}
return 10;
};
Runnable b = () -> {
int count = 7;
while (--count > 0) {
System.out.println("Runnable");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Future<Integer> retA = service.submit(a);
Integer result = retA.get(7, TimeUnit.SECONDS);
System.out.println(result);
service.submit(b);
}
运行的结果
Callable
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: throw !
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:206)
at com.mininglamp.inference.SinglePoolTests.main(SinglePoolTests.java:42)
Caused by: java.lang.IllegalArgumentException: throw !
at com.mininglamp.inference.SinglePoolTests.lambda$main$0(SinglePoolTests.java:26)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
任务失败后就获得结果当然是出现异常的结果,Runnable也测试了一下,虽然runnale是没有返回值的
但是,还是会返回一个Future<?>类型的对象,然后调用get方法获取最终结果,也能看见异常出现在System.err中, 注意要用Future类中的这个方法
V get(long timeout, TimeUnit unit)
3.最后 new Thread() 是在执行完后会自动的销毁,而后者如果没有显式调用的话会一直存在
这个特点也提醒开发者,用完一定要关闭,温柔点用Shutdown就好。
service.shutdown();