一 几个常见的对比
1 Runnable
vs Callable
Runnable
自 Java 1.0 以来一直存在,但Callable
仅在 Java 1.5 中引入,目的就是为了来处理Runnable
不支持的用例。
Runnable
接口不会返回结果或抛出检查异常,但是**Callable
接口**可以。
所以,如果任务不需要返回结果或抛出异常推荐使用 Runnable
接口,这样代码看起来会更加简洁。
工具类 Executors
可以实现 Runnable
对象和 Callable
对象之间的相互转换。(Executors.callable(Runnable task
)或 Executors.callable(Runnable task,Object resule)
)。
Runnable.java
@FunctionalInterface public interface Runnable { /** * 被线程执行,没有返回值也无法抛出异常 */ public abstract void run(); }
Callable.java
@FunctionalInterface public interface Callable<V> { /** * 计算结果,或在无法这样做时抛出异常。 * @return 计算得出的结果 * @throws 如果无法计算结果,则抛出异常 */ V call() throws Exception; }
2 execute()
vs submit()
-
execute()
方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否; -
submit()
方法用于提交需要返回值的任务。线程池会返回一个Future
类型的对象,通过这个Future
对象可以判断任务是否执行成功 ,并且可以通过Future
的get()
方法来获取返回值,get()
方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)
方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
我们以 AbstractExecutorService
接口中的一个 submit()
方法为例子来看看源代码:
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; }
上面方法调用的 newTaskFor
方法返回了一个 FutureTask
对象。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); }
我们再来看看execute()
方法:
public void execute(Runnable command) { ... }
3 shutdown()
VSshutdownNow()
-
shutdown()
:关闭线程池,线程池的状态变为SHUTDOWN
。线程池不再接受新任务了,但是队列里的任务得执行完毕。 -
shutdownNow()
:关闭线程池,线程的状态变为STOP
。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的 List。
4 isTerminated()
VS isShutdown()
-
isShutDown
当调用shutdown()
方法后返回为 true。 -
isTerminated
当调用shutdown()
方法后,并且所有提交的任务完成后返回为 true
二.Callable
+ThreadPoolExecutor
示例代码
MyCallable.java
import java.util.concurrent.Callable; public class MyCallable implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(1000); //返回执行当前 Callable 的线程名字 return Thread.currentThread().getName(); } }
CallableDemo.java
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class CallableDemo { private static final int CORE_POOL_SIZE = 5; private static final int MAX_POOL_SIZE = 10; private static final int QUEUE_CAPACITY = 100; private static final Long KEEP_ALIVE_TIME = 1L; public static void main(String[] args) { //使用阿里巴巴推荐的创建线程池的方式 //通过ThreadPoolExecutor构造函数自定义参数创建 ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<>(QUEUE_CAPACITY), new ThreadPoolExecutor.CallerRunsPolicy()); List<Future<String>> futureList = new ArrayList<>(); Callable<String> callable = new MyCallable(); for (int i = 0; i < 10; i++) { //提交任务到线程池 Future<String> future = executor.submit(callable); //将返回值 future 添加到 list,我们可以通过 future 获得 执行 Callable 得到的返回值 futureList.add(future); } for (Future<String> fut : futureList) { try { System.out.println(new Date() + "::" + fut.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } //关闭线程池 executor.shutdown(); } }
Output:
Wed Nov 13 13:40:41 CST 2019::pool-1-thread-1 Wed Nov 13 13:40:42 CST 2019::pool-1-thread-2 Wed Nov 13 13:40:42 CST 2019::pool-1-thread-3 Wed Nov 13 13:40:42 CST 2019::pool-1-thread-4 Wed Nov 13 13:40:42 CST 2019::pool-1-thread-5 Wed Nov 13 13:40:42 CST 2019::pool-1-thread-3 Wed Nov 13 13:40:43 CST 2019::pool-1-thread-2 Wed Nov 13 13:40:43 CST 2019::pool-1-thread-1 Wed Nov 13 13:40:43 CST 2019::pool-1-thread-4 Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5