转载:线程池
线程提交的两种方式
ExecutorService poll3 = Executors.newCachedThreadPool();
for (int i = 0; i < 2; i++) {
poll3.execute(new TargetTask());
poll3.submit(new TargetTask());
}
- execute方法
void execute(Runnable command)
: Executor接口中的方法 - submit方法
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
这3个submit方法都是ExecutorService接口中的方法(ExecutorService接口 是Executor接口的子类)
区别
- execute 方法只能接收 Runnable 类型的参数, submit 方法可以接收 Runnable 和 Callable 两种类型的参数
- execute 方法没有返回值,submit 方法有返回值(原因是Callable 类型任务有返回值,Runnable 类型任务没有返回值)
- submit()方便子线程的异常处理
@Slf4j
public class ExecutorsTest {
static class TargetTask implements Runnable {
public static final int SLEEP_GAP = 1000;
// AtomicInteger 提供了一种线程安全的方式来对整数进行操作。它可以保证多个线程同时对同一个AtomicInteger对象进行操作时,不会出现数据竞争和不一致的情况
static AtomicInteger taskNo = new AtomicInteger(0);
String taskName;
@Override
public void run() {
log.info(taskName + "is running ...");
try {
Thread.sleep(SLEEP_GAP);
} catch (Exception e) {
log.error(taskName + "running error !");
e.printStackTrace();
}
log.info(taskName + "is end ...");
}
TargetTask() {
taskName = "task_" + taskNo;
taskNo.incrementAndGet();
}
}
static class TargetTaskWithError extends TargetTask {
public void run() {
super.run();//执行父类的run方法
// 强行抛出异常
throw new RuntimeException("Error from " + taskName);
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService poll6 = Executors.newFixedThreadPool(3);
// execute 方式不关心任务执行的结果,没有返回值,不能处理异常
try{
poll6.execute(new TargetTaskWithError());
}catch (Exception e){
log.error("task has Exception !");
e.printStackTrace();
}
// submit 方式有返回值,方便处理异常
// Future future = poll6.submit(new TargetTaskWithError());
// try {
// if (null == future.get()) {
// log.info(" task no Exception !");
// }
// } catch (Exception e) {
// log.error("task has Exception !");
// e.printStackTrace();
// }
poll6.shutdown();
}
}
如图:
使用 submit 向线程池提交任务可以处理异常,打印了task has Exception !
使用 execute 向线程池提交任务不能处理异常,未打印了task has Exception !