-
耳熟能详的两种创建线程的方式是扩展Thread和实现Runnable接口
但是它们有一个固有缺陷: 无法获取执行的结果
为了解决这个问题, Callable诞生了
-
Callable
(1) 在java.util.concurrent包下, 是一个泛型接口
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
(2) 接口中只有一个call()方法, 类似于Runnable中的run()方法,但是run()方法既没有返回值也不抛出异常
public interface Runnable { public abstract void run(); }
(3) JavaDoc中说, Executor类中提供了静态方法, 可以将普通的Runnable转换为Callable(这种适合集体转换, 例如都返回true或者都返回false)
Executor中提供的方法
public static <T> Callable<T> callable(Runnable task, T result); public static Callable<Object> callable(Runnable task);
-
Future
(1) 是一个java.util.concurrent中的接口, 它提供了几个5个方法
boolean cancel(boolean mayInterruptIfRunning); --取消未完成的任务 boolean isCancelled(); --判断是否任务已经取消 boolean isDone(); --判断任务是否完成 V get() throws InterruptedException, ExecutionException; --获取任务的完成结果(获取不到就阻塞) V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; --获取任务的完成结果,带定时
(2) Future常常与线程池一起使用, 例如executor.submit(Callable task);会返回一个Future对象
-
FutureTask
(1) FutureTask是一个java.util.concurrent中的类, 它实现了RunnableFuture接口; 而RunnableFuture接口实现了Runnable和Future接口, 所以FutureTask对象可以既可以传入Thread的构造参数中, 也可以作为Future的接口实例
(2) FutureTask的构造函数形式有两种
public FutureTask(Callable<V> callable); 传入一个callable对象 public FutureTask(Runnable runnable, V result); 传入一个runnable对象和一个result结果用于get()
-
示例
(1) 不使用线程池
class Example { static class MyCallable implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(1000); //return the thread name executing this callable task return Thread.currentThread().getName(); } } public static void main(String args[]) { List<FutureTask<String>> taskList = new ArrayList<>(); // run each task for (int i = 0; i < 10; i++) { FutureTask<String> task = new FutureTask<>(new MyCallable()); taskList.add(task); Thread thread = new Thread(task, String.valueOf(i)); thread.start(); } // get result of myCallable.call()(but from future.get() directly); for (FutureTask<String> task: taskList) { try { System.out.println(task.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
(2) 使用线程池
class Example { static class MyCallable implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(1000); return Thread.currentThread().getName(); } } public static void main(String args[]) { //Get ExecutorService from Executors utility class, thread pool size is 10 ExecutorService executor = Executors.newFixedThreadPool(10); //create a list to hold the Future object associated with Callable List<Future<String>> list = new ArrayList<Future<String>>(); //Create MyCallable instance Callable<String> callable = new MyCallable(); for (int i = 0; i < 100; i++) { //submit Callable tasks to be executed by thread pool Future<String> future = executor.submit(callable); //add Future to the list, we can get return value using Future list.add(future); } for (Future<String> fut : list) { try { System.out.println(new Date() + "::" + fut.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } //shut down the executor service now executor.shutdown(); } }
8_关于Callable, Future和FutureTask
最新推荐文章于 2024-03-11 08:00:00 发布