Java线程和多线程(十三)——Callable,Future,FutureTask
来源:互联网 发布:352空气净化器 知乎 编辑:程序博客网 时间:2024/06/05 05:13
在Java多线程之中,Callable
和Future
的使用时非常广泛的。在之前的文章中,我们了解了关于Java线程池基础的一些内容,知道如何提交Runnable
的任务。但是,Runnable
的任务是无法有返回值,也不能抛出异常的。而有些时候,我们希望一个线程能够有一些返回值。在Java 5中,引入了java.util.concurrent.Callable
接口,这个接口很类似于Runnable
接口,但是可以返回一个对象,或者抛出异常。
Java Callable
Java的Callable
接口使用了泛型来定义返回的对象的类型。Executors
类提供了一些很实用的方法来在线程池中执行Callable
的任务。因为Callable
的任务通过并行的方式来运行,所以我们需要等待返回的对象。
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;}
Java Future
Java的Callable
对象返回的就是java.util.concurrent.Future
对象。通过使用Java Future
对象,我们可以知道Callable
任务的执行状态,并且获得返回的对象。Future
接口提供get()
方法来让开发者可以等待Callable
任务的执行,然后获得对应的结果。
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}
Java Future提供了一个cancel()
方法来取消关联的Callable
任务的执行。其中的get()
方法是包含一个重载的方法的,我们可以指定等待的时间,而不需要无限期的等待Callable
任务的执行。这个方法可以有效的防止一个线程的无限期的阻塞。 Future
也提供一个isDone()
和一个isCancelled()
方法来找到其关联的Callable
任务的执行状态。
下面是使用Callable
的例子,是在一秒之后返回执行任务的名字。我们通过使用Executor
框架来并行执行100个任务,然后用Future
来获得任务的执行结果。
package com.sapphire.threads;import java.util.ArrayList;import java.util.Date;import java.util.List;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 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[]){ //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 { //print the return value of Future, notice the output delay in console // because Future.get() waits for task to get completed System.out.println(new Date()+ "::"+fut.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } //shut down the executor service now executor.shutdown(); }}
当我们运行上面程序的时候,我们的输出会有延迟,因为Future的get()
方法会一直等待Callable
的任务执行完毕。同时需要注意的是,线程池中,我们仅仅会有10个线程来处理之前定义的Callable
任务。
下面是上面程序的输出结果:
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2...
当我们想要覆盖掉
Future
接口的一些行为的时候,举例来说,假设我们需要覆盖其中的get()
方法来做一些超时处理而不进行持续等待等操作的时候。Java中的FutureTask
类在这种时候就会非常有用了,它是Future
接口的实现类。
FutureTask
在上面,我们了解到使用Callable
以及Future
接口来处理多线程的一些便利之处。
而FutureTask
是Future
接口的一个基础实现,并且提供了异步处理的功能,FutureTask
包含了一些方法来启动或者取消任务,也包含一些方法来返回Future
的状态,来确认Future
是完成了还是去掉了。我们需要一个Callable
对象来创建一个FutureTask
然后,我们可以通过ThreadPoolExecutor
来异步处理这些任务。
下面是FutureTask
的代码举例,因为FutureTask
是需要Callable
的,所以我们来创建一个Callable
的实现:
package com.sapphire.threads;import java.util.concurrent.Callable;public class MyCallable implements Callable<String> { private long waitTime; public MyCallable(int timeInMillis){ this.waitTime=timeInMillis; } @Override public String call() throws Exception { Thread.sleep(waitTime); //return the thread name executing this callable task return Thread.currentThread().getName(); }}
下面是一个FutureTask
方法的例子,下面展示的是关于使用FutureTask
方法的一些举例:
package com.sapphire.threads;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;public class FutureTaskExample { public static void main(String[] args) { MyCallable callable1 = new MyCallable(1000); MyCallable callable2 = new MyCallable(2000); FutureTask<String> futureTask1 = new FutureTask<String>(callable1); FutureTask<String> futureTask2 = new FutureTask<String>(callable2); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(futureTask1); executor.execute(futureTask2); while (true) { try { if(futureTask1.isDone() && futureTask2.isDone()){ System.out.println("Done"); //shut down executor service executor.shutdown(); return; } if(!futureTask1.isDone()){ //wait indefinitely for future task to complete System.out.println( "FutureTask1 output="+futureTask1.get()); } System.out.println("Waiting for FutureTask2 to complete"); String s = futureTask2.get(200L, TimeUnit.MILLISECONDS); if(s !=null){ System.out.println("FutureTask2 output="+s); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }catch(TimeoutException e){ //do nothing } } }}
当我们运行上面的程序,你会发现,有一段时间是不会输出任何东西到控制台的,因为FutureTask
的get()
方法会等待任务的完成,然后才会返回输出的对象。在FutureTask
中也有一个重载的方法会等待指定的时间。需要注意的是,当调用isDone()
方法来确定程序一旦结束,任务也会完成。
输出如下:
FutureTask1 output=pool-1-thread-1Waiting for FutureTask2 to completeWaiting for FutureTask2 to completeWaiting for FutureTask2 to completeWaiting for FutureTask2 to completeWaiting for FutureTask2 to completeFutureTask2 output=pool-1-thread-2Done
从上面的例子来说是没有使用到FutureTask
的便利之处的,但是当我们想要覆盖掉Future
接口方法的实现,而不像实现Future
接口的每一个方法的时候,我们就可以考虑使用FutureTask
。
- Java线程和多线程(十三)——Callable,Future,FutureTask
- Java多线程(二)——Callable、Future和FutureTask
- Java多线程——Callable、Future和FutureTask
- Java多线程之 Callable、Future和FutureTask
- Java多线程之Callable、Future和FutureTask
- Java多线程:Callable、Future和FutureTask
- Java多线程:Callable、Future和FutureTask
- Java多线程之Callable、Future和FutureTask
- java线程(3)——详解Callable、Future和FutureTask
- Java多线程 Callable Future FutureTask
- 【Java多线程】-Callable,Future,FutureTask
- Android(Java)之多线程结果返回——Future 、FutureTask、Callable、Runnable
- Java多线程:Callable、ExecutorService、CountDownLatch、Future和FutureTask
- java多线程编程之Callable、Future和FutureTask。
- Java多线程编程:Callable、Future和FutureTask浅析
- Java多线程编程:Callable、Future和FutureTask浅析
- java多线程系列(七)---Callable、Future和FutureTask
- Java多线程编程:Callable、Future和FutureTask浅析
- jsp与ajax的数据传递
- PopupWindow基本使用方法
- 序列化和反序列化
- 超详细图解:自己架设NuGet服务器
- 你必须要知道的九种浏览器端缓存
- Java线程和多线程(十三)——Callable,Future,FutureTask
- session里的数据为什么无缘无故丢失
- How to disable the scheduler using SCHEDULER_DISABLED attribute in 10g (文档 ID 1491941.1)
- 使用PHP一键生成MySQL数据库字典
- Nginx 之一:编译安装nginx 1.8.1 及配置
- gatttool Userguide
- Web设计模式 之 - MVC vs. MVP vs. MVVM
- CentOS 7 安装 MySQL
- IARPUninstallStringLauncher绕过UAC