Home  >  Article  >  Java  >  The relationship and usage between Future and FutureTask in java (with code)

The relationship and usage between Future and FutureTask in java (with code)

不言
不言forward
2018-10-15 15:46:462453browse

The content this article brings to you is about the relationship and usage between Future and FutureTask in Java (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you. .

Future and FutureTask are both used to obtain the return results of thread execution. Below we will give a general introduction and analysis of the relationship and use between the two

1. Future andIntroduction to FutureTask

Future is located under the java.util.concurrent package, it is an interface

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;
}

## There are 5 methods declared in the #Future interface. The function of each method is introduced below:

The cancel method is used to cancel the task. It returns true if the cancellation is successful and false if the cancellation fails. The parameter mayInterruptIfRunning is set to false, which means that interruption is not allowed when the thread is running, and set to true, which means it is allowed. Specifically, it can be divided into the following three situations:

1. If the task has been completed, whether mayInterruptIfRunning is true or false, it will return false. This is because the task you want to cancel has been completed, and the task cancellation is considered to have failed. ;

2. If the task is being executed, true will be returned regardless of whether mayInterruptIfRunning is true or false. It's just that when mayInterruptIfRunning is true, the thread will be interrupted, and when false, the thread will not be interrupted and will complete execution.

3. If the task has not been executed, whether mayInterruptIfRunning is true or false, it will return true.

The isCancelled method is used to determine whether the task has been successfully canceled. If the cancel method is successful, it returns true, otherwise it returns false.

isDone is used to determine whether the task is completed, and returns true if the task is completed. Task completion includes normal completion, task cancellation, and task exception, all of which return true

get() method is used to obtain the execution result. This method will cause blocking and will not return until the task execution is completed;

get(long timeout, TimeUnit unit) is used to obtain the execution result. If the result is not obtained within the specified time, a java.util.concurrent.TimeoutException exception is thrown

FutureTask implements RunnableFuture interface, and RunnableFuture inherits the Futured94943c0b4933ad8cac500132f64757f and Runnable interfaces, so FutureTask not only implements all the methods of the Futured94943c0b4933ad8cac500132f64757f interface, but also has its own run method. We can take a look at its class diagram

, Future and FutureTaskUsage and analysis 1. When using Future, we need to implement the Callable interface and obtain the returned Future object through the submit method of the ExecutorService interface.

2. When using FutureTask, according to the constructor of FutureTask, we can see that FutureTask has both You can receive the implementation class of Callable or the implementation class of Runnable. When you pass in the implementation class of Callable, you can get the result of thread execution; when you pass in the implementation class of Runnable, since the implementation of Runnable has no return value, you need to pass in a thread completion identifier that you set, that is, result. Then when the thread ends, the original result value you passed in will be returned to you. The constructor of FutureTask is as follows:

public class FutureTask<V> implements RunnableFuture<V>{
     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);//runnable转化为callable 
        this.state = NEW;       // ensure visibility of callable
     }
}

Next, let’s look at Future Specific usage code for FutureTask:

       // 执行任务 实现Runnable
        FutureTaskJobRunnable taskRun = new FutureTaskJobRunnable();
        // 执行任务 实现Callable
        FutureTaskJobCallable taskCall = new FutureTaskJobCallable();
        String val = "ok";
        // 线程运行成功后把,返回你传入的val值
        FutureTask<String> futureTaskRun = new FutureTask<String>(taskRun, val);
        // 线程运行,返回线程执行的结果
        FutureTask<String> futureTaskCall = new FutureTask<String>(taskCall);
        //声明线程池
        ExecutorService executor = Executors.newCachedThreadPool();        
        //Future
        Future<String> future =  executor.submit(taskCall);
        System.out.println(future.get());
        //FutureTask
        executor.submit(futureTaskCall);
        System.out.println(futureTaskCall.get());
        //FutureTask自定义线程执行
        new Thread(futureTaskRun).start();
        System.out.println(futureTaskRun.get());

public class FutureTaskJobCallable implements Callable<String>{
    
    public String call() throws Exception {
        System.out.println("FutureTaskJobCallable已经执行了哦");
        Thread.sleep(1000);
        return "返回结果";
    }
}
public class FutureTaskJobRunnable implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("FutureTaskJobRunnable已经执行了哦");
    }
}

According to the above code, we submit the method from the ExecutorService interface Let’s start by taking a look at the specific implementation of the submit method in the AbstractExecutorService class.

public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

You can see that when you use the submit method to submit a task, it will be converted into a FutureTask object through the newTaskFor method, so let’s analyze the three points in the above code in detail. Situation:

1. If you pass in the Runaable class or Callable class that you implemented yourself, then the sumbit method will naturally help you automatically encapsulate it into a FutureTask object, and get the result through the Future object after running.

2、你传入的已经是个自己构造的FutureTask对象,由于FutureTask其实是实现了Runnable接口的,它本身就是个Runaable实现类, sumbit方法还是会将它视为Runnable类来进行封装,并最终会执行FutureTask自己的run方法,一系列实现都在你传入的FutureTask对象内完成,所以你可以直接通过自己构建的FutureTask获取结果;

3、自己单独声明线程运行,跟第2点类似,FutureTask本身就是个Runnabel实现类,自然可以做为参数传入Thread运行;

那么我们把自定义的Runnable、Callable实现类做为参数构造FutureTask后,FuttureTask是如何运行的呢,我们可以看下FuttureTask中具体的代码实现

//你传入的Runnable与Callable实现类都会在构造函数中转化为Callable
private Callable<V> callable;
    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;//你传入的实现类
            if (c != null && state == NEW) {
                V result;//返回值
                boolean ran;
                try {
                    result = c.call();//运行后返回结果
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

可以看到FutureTask类本身的run方法,就是执行Runnable、Callable的实现类并获取返回结果的过程。

所以ExecutorService接口中submit方法归根结底还是要把你传入的对象封装成FutureTask对象,并通过FutureTask类的内部实现来获取结果的,返回的Future接口对象也要依赖于FutureTask实例化的,所以无论是直接传入自己的Runnable、Callable实现类还是构建FutureTask传入,本质上都是通过FutureTask去实现,没有什么区别;

The above is the detailed content of The relationship and usage between Future and FutureTask in java (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete