ExecutorService中submit和execute的区别:
1、方法execute()没有返回值,而submit()方法可以有返回值(通过Callable和Future接口)
2、方法execute()在默认情况下异常直接抛出(即打印堆栈信息),不能捕获,但是可以通过自定义ThreadFactory的方式进行捕获(通过setUncaughtExceptionHandler方法设置),而submit()方法在默认的情况下可以捕获异常。
3、方法execute()提交的未执行的任务可以通过remove(Runnable)方法删除,而submit()提交的任务即使还未执行也不能通过remove(Runnable)方法删除。
4、execute只能接受Runnable类型的任务。submit不管是Runnable还是Callable类型的任务都可以接受,但是Runnable返回值均为void,所以使用Future的get()获得的还是null。
5、execute中抛出异常。
① execute中的是Runnable接口的实现,所以只能使用try、catch来捕获Checked。
Exception,通过实现UncaughtExceptionHande接口处理UncheckedException, 即和普通线程的处理方式完全一致。
②submit中抛出异常
不管提交的是Runnable还是Callable类型的任务,如果不对返回值Future调用get()方法,都会吃掉异常。
ExecutorService中submit和execute的区别有三点:
1、接收的参数不同
2、submit有返回值,而execute没有。
用到返回值的例子,比如说应用中有很多个做validation的task,用户希望所有的task执行完,然后每个task告诉主程序执行结果,是成功还是失败,如果是失败,原因是什么。然后就可以把所有失败的原因综合起来发给调用者。
3、submit方便Exception处理,而execute处理异常比较麻烦。
在task里会抛出checked或者unchecked exception,而用户又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。
举例说明:
import java.util.ArrayList; 。
import java.util.List; 。
import java.util.Random; 。
import java.util.concurrent.Callable; 。
import java.util.concurrent.ExecutionException; 。
import java.util.concurrent.ExecutorService; 。
import java.util.concurrent.Executors; 。
import java.util.concurrent.Future; 。
public class ExecutorServiceTest { 。
public static void main(String[] args) { 。
ExecutorService executorService = Executors.newCachedThreadPool(); 。
List<Future> resultList = new ArrayList<Future>(); 。
// 创建10个任务并执行
for (int i = 0; i < 10; i++) { 。
// 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中 。
Future future = executorService.submit(new TaskWithResult(i)); 。
// 将任务执行结果存储到List中 。
resultList.add(future); 。
}
executorService.shutdown(); 。
// 遍历任务的结果
for (Future fs : resultList) { 。
try {
System.out.println(fs.get()); // 打印各个线程(任务)执行的结果 。
} catch (InterruptedException e) { 。
e.printStackTrace(); 。
} catch (ExecutionException e) { 。
executorService.shutdownNow(); 。
e.printStackTrace(); 。
return;
}
}
}
}
class TaskWithResult implements Callable { 。
private int id; 。
public TaskWithResult(int id) { 。
this.id = id;
}
/**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
*
* @return
* @throws Exception 。
*/
public String call() throws Exception { 。
System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName()); 。
if (new Random().nextBoolean()) 。
throw new TaskException("Meet error in task." + Thread.currentThread().getName()); 。
// 一个模拟耗时的操作
for (int i = 999999999; i > 0; i--) 。
;
return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName(); 。
}
}
class TaskException extends Exception { 。
public TaskException(String message) { 。
super(message); 。
}
}
执行的结果类似于:
call()方法被自动调用,干活!!! pool-1-thread-1 。
call()方法被自动调用,干活!!! pool-1-thread-2 。
call()方法被自动调用,干活!!! pool-1-thread-3 。
call()方法被自动调用,干活!!! pool-1-thread-5 。
call()方法被自动调用,干活!!! pool-1-thread-7 。
call()方法被自动调用,干活!!! pool-1-thread-4 。
call()方法被自动调用,干活!!! pool-1-thread-6 。
call()方法被自动调用,干活!!! pool-1-thread-7 。
call()方法被自动调用,干活!!! pool-1-thread-5 。
call()方法被自动调用,干活!!! pool-1-thread-8 。
call()方法被自动调用,任务的结果是:0 pool-1-thread-1 。
call()方法被自动调用,任务的结果是:1 pool-1-thread-2 。
java.util.concurrent.ExecutionException: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3 。
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222) 。
at java.util.concurrent.FutureTask.get(FutureTask.java:83) 。
at com.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29) 。
Caused by: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3 。
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57) 。
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1) 。
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 。
at java.util.concurrent.FutureTask.run(FutureTask.java:138) 。
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 。
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 。
at java.lang.Thread.run(Thread.java:619)。
接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且可以让任务在后台执行。一个 ExecutorService 实例因此特别像一个线程池。事实上,在 java.util.concurrent 包中的 ExecutorService 的实现就是一个线程池的实现。
这里有一个简单的使用Java 实现的 ExectorService 样例:
使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService ,上述代码创建了一个可以容纳10个线程任务的线程池。其次,向 execute() 方法中传递一个异步的 Runnable 接口的实现,这样做会让 ExecutorService 中的某个线程执行这个 Runnable 线程。
线程池的架构图如下:
1. Executor
它是"执行者"接口,它是来执行任务的。准确的说,Executor提供了execute()接口来执行已提交的 Runnable 任务的对象。Executor存在的目的是提供一种将"任务提交"与"任务如何运行"分离开来的机制。它只包含一个函数接口。
2. Executors
Executors是个静态工厂类。它通过静态工厂方法返回ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 等类的对象。
3. ExecutorService。
ExecutorService继承于Executor。它是"执行者服务"接口,它是为"执行者接口Executor"服务而存在的;准确的话,ExecutorService提供了"将任务提交给执行者的接口(submit方法)","让执行者执行任务(invokeAll, invokeAny方法)"的接口等等。
ExecutorService中shutdown是的意思如下:
1、当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态,以后不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。
2、此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
3、 与它相似的还有一个shutdownNow(),它通过调用Thread.interrupt来实现线程的立即退出。
4、ExecutorService是Executor直接的扩展接口,也是最常用的线程池接口,我们通常见到的线程池定时任务线程池都是它的实现类。
5、Executor的实现提供的一些方法可以返回一个 Future , 通过它我们可以跟踪到异步任务的执行和停止。
6、ExecutorService(线程池)可以被关闭来拒绝新任务。有两个不同的方法来关闭。 shutdown方法 在关闭 ExecutorService 之前等待提交的任务执行完成。