Java中的Runnable、Callable、Future、FutureTask

来源:互联网 发布:c语言自学入门 编辑:程序博客网 时间:2024/05/08 04:40

FutureTask 

FutureTask正如其名字中的Future,其使用Future定义的类及其计算方法。它可以start, cancel其计算操作。还可以使用get查询计算的计算。


package java_test;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/** * 测试FutureTask的用法,如果不想分支线程阻塞主线程,又想取得分支线程的执行结果,就用FutureTask * * @author  * */public class FutureTaskTest {/** * @param args */public static void main(String[] args) {CountNum cn = new CountNum(0);// FutureTask<Integer> 这里的表示返回的是IntegerFutureTask<Integer> ft = new FutureTask<Integer>(cn);Thread td = new Thread(ft);System.out.println("futureTask开始执行计算:" + System.currentTimeMillis());td.start();System.out.println("main 主线程可以做些其他事情:" + System.currentTimeMillis());try {// futureTask的get方法会阻塞,知道可以取得结果为止Integer result = ft.get();System.out.println("计算的结果是:" + result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("取得分支线程执行的结果后,主线程可以继续处理其他事项");}}class CountNum implements Callable {private Integer sum;public CountNum(Integer sum) {this.sum = sum;}public Object call() throws Exception {for (int i = 0; i < 100; i++) {sum = sum + i;}// 休眠5秒钟,观察主线程行为,预期的结果是主线程会继续执行,到要取得FutureTask的结果是等待直至完成。Thread.sleep(3000);System.out.println("futureTask 执行完成" + System.currentTimeMillis());return sum;}}


futureTask开始执行计算:1441628133867main 主线程可以做些其他事情:1441628133867futureTask 执行完成1441628136868计算的结果是:4950取得分支线程执行的结果后,主线程可以继续处理其他事项


JavaDoc中的说明:
A cancellable asynchronous computation. This class provides a base implementation of Future, with methods to start and cancel a computation, query to see if the computation is complete, and retrieve the result of the computation. The result can only be retrieved when the computation has completed; the get methods will block if the computation has not yet completed. Once the computation has completed, the computation cannot be restarted or cancelled (unless the computation is invoked using runAndReset).A FutureTask can be used to wrap a Callable or Runnable object. Because FutureTask implements Runnable, a FutureTask can be submitted to an Executor for execution.In addition to serving as a standalone class, this class provides protected functionality that may be useful when creating customized task classes.Parameters:<V> The result type returned by this FutureTask's get methodsSince:1.5


如果有多个FutureTask要执行批量运算,从而充分的利用多核CPU,可以参考下面的代码:

package java_test;import java.util.ArrayList;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.FutureTask;/** * 测试多核时代,充分的利用CPU来运算数据,并且处理返回的结果 * * @author Administrator * */public class FutureTaskAndExecutor {/** * @param args */public static void main(String[] args) {List<FutureTask<Integer>> list = new ArrayList<FutureTask<Integer>>();// 创建线程池,线程池的大小和List.size没有啥必然的关系,一般的原则是<=list.size,多出来浪费不好ExecutorService exec = Executors.newFixedThreadPool(5);for (int i = 10; i < 20; i++) {// 创建对象FutureTask<Integer> ft = new FutureTask<Integer>(new GetSum(i));// 添加到list,方便后面取得结果list.add(ft);// 一个个提交给线程池,当然也可以一次性的提交给线程池,exec.invokeAll(list);exec.submit(ft);}// 开始统计结果Integer total = 0;for (FutureTask<Integer> tempFt : list) {try {total = total + tempFt.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}// 处理完毕,一定要记住关闭线程池,这个不能在统计之前关闭,因为如果线程多的话,执行中的可能被打断exec.shutdown();System.out.println("多线程计算后的总结果是:" + total);}}/** * 这个类就是统计下简单的加法(从1 到total) * * @author Administrator * */class GetSum implements Callable {private Integer total;private Integer sum = 0;public GetSum(Integer total) {this.total = total;}public Object call() throws Exception {for (int i = 1; i < total + 1; i++) {sum = sum + i;}System.out.println(Thread.currentThread().getName() + " sum:" + sum);return sum;}}

输出结果:

pool-1-thread-2 sum:66pool-1-thread-5 sum:105pool-1-thread-4 sum:91pool-1-thread-1 sum:55pool-1-thread-5 sum:153pool-1-thread-1 sum:171pool-1-thread-3 sum:78pool-1-thread-5 sum:190pool-1-thread-4 sum:136pool-1-thread-2 sum:120多线程计算后的总结果是:1165


====================

Java中和线程有关的其它几个接口

Runnable

其中Runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。Runnable的声明如下 :

public interface Runnable {    /**     * When an object implementing interface <code>Runnable</code> is used     * to create a thread, starting the thread causes the object's     * <code>run</code> method to be called in that separately executing     * thread.     * <p>     *     * @see     java.lang.Thread#run()     */    public abstract void run();}


Callable

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。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;}

可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。


Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行

取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(Future简介)。Future声明如下 :

/*** @see FutureTask * @see Executor * @since 1.5 * @author Doug Lea * @param <v> The result type returned by this Future's <tt>get</tt> method */public interface Future<v> {     /**     * Attempts to cancel execution of this task.  This attempt will     * fail if the task has already completed, has already been cancelled,     * or could not be cancelled for some other reason. If successful,     * and this task has not started when <tt>cancel</tt> is called,     * this task should never run.  If the task has already started,     * then the <tt>mayInterruptIfRunning</tt> parameter determines     * whether the thread executing this task should be interrupted in     * an attempt to stop the task.     *     */    boolean cancel(boolean mayInterruptIfRunning);     /**     * Returns <tt>true</tt> if this task was cancelled before it completed     * normally.     */    boolean isCancelled();     /**     * Returns <tt>true</tt> if this task completed.     *     */    boolean isDone();     /**     * Waits if necessary for the computation to complete, and then     * retrieves its result.     *     * @return the computed result     */    V get() throws InterruptedException, ExecutionException;     /**     * Waits if necessary for at most the given time for the computation     * to complete, and then retrieves its result, if available.     *     * @param timeout the maximum time to wait     * @param unit the time unit of the timeout argument     * @return the computed result     */    V get(long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException;}


FutureTask

FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了Futrue这两个接口,

public class FutureTask<V> implements RunnableFuture<V> {     // ... ... }



public interface RunnableFuture<V> extends Runnable, Future<V> {    /**     * Sets this Future to the result of its computation     * unless it has been cancelled.     */    void run();}


另外它还可以包装Runnable和Callable, 由构造函数注入依赖。
public FutureTask(Callable<v> callable) {    if (callable == null)        throw new NullPointerException();    this.callable = callable;    this.state = NEW;       // ensure visibility of callable} public FutureTask(Runnable runnable, V result) {    this.callable = Executors.callable(runnable, result);    this.state = NEW;       // ensure visibility of callable}


可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。该适配函数的实现如下 :

public static <t> Callable<t> callable(Runnable task, T result) {    if (task == null)        throw new NullPointerException();    return new RunnableAdapter<t>(task, result);}

RunnableAdapter适配器

/** * A callable that runs given task and returns given result */static final class RunnableAdapter<t> implements Callable<t> {    final Runnable task;    final T result;    RunnableAdapter(Runnable task, T result) {        this.task = task;        this.result = result;    }    public T call() {        task.run();        return result;    }}


由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。

并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、

Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。


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;import java.util.concurrent.FutureTask; /** *  * @author mrsimple * */public class RunnableFutureTask {     /**     * ExecutorService     */    static ExecutorService mExecutor = Executors.newSingleThreadExecutor();     /**     *      * @param args     */    public static void main(String[] args) {        runnableDemo();        futureDemo();    }     /**     * runnable, 无返回值     */    static void runnableDemo() {         new Thread(new Runnable() {             @Override            public void run() {                System.out.println("runnable demo : " + fibc(20));            }        }).start();    }     /**     * 其中Runnable实现的是void run()方法,无返回值;Callable实现的是 V     * call()方法,并且可以返回执行结果。其中Runnable可以提交给Thread来包装下     * ,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。     */    static void futureDemo() {        try {            /**             * 提交runnable则没有返回值, future没有数据             */            Future<!--?--> result = mExecutor.submit(new Runnable() {                 @Override                public void run() {                    fibc(20);                }            });             System.out.println("future result from runnable : " + result.get());             /**             * 提交Callable, 有返回值, future中能够获取返回值             */            Future<integer> result2 = mExecutor.submit(new Callable<integer>() {                @Override                public Integer call() throws Exception {                    return fibc(20);                }            });             System.out                    .println("future result from callable : " + result2.get());             /**             * FutureTask则是一个RunnableFuture<v>,即实现了Runnbale又实现了Futrue<v>这两个接口,             * 另外它还可以包装Runnable(实际上会转换为Callable)和Callable             * <v>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行             * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。             */            FutureTask<integer> futureTask = new FutureTask<integer>(                    new Callable<integer>() {                        @Override                        public Integer call() throws Exception {                            return fibc(20);                        }                    });            // 提交futureTask            mExecutor.submit(futureTask) ;            System.out.println("future result from futureTask : "                    + futureTask.get());         } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }    }     /**     * 效率底下的斐波那契数列, 耗时的操作     *      * @param num     * @return     */    static int fibc(int num) {        if (num == 0) {            return 0;        }        if (num == 1) {            return 1;        }        return fibc(num - 1) + fibc(num - 2);    } }








0 0
原创粉丝点击