FutureTask详解以及实现

FutureTask

  我们先来看一下FutureTask的实现:

1

public class FutureTask<V> implements RunnableFuture<V>

   FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

1

2

3

public interface RunnableFuture<V> extends Runnable, Future<V> {

    void run();

}

   可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

  FutureTask提供了2个构造器:

1

2

3

4

public FutureTask(Callable<V> callable) {

}

public FutureTask(Runnable runnable, V result) {

}

  事实上,FutureTask是Future接口的一个唯一实现类。

FutureTask使用

可以把FutureTask交给Executor执行;也可以通ExecutorService.submit(…)方法返回一个FutureTask,然后执行FutureTask.get()方法或FutureTask.cancel(…)方法。除此以外,还可以单独使用FutureTask。
当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用FutureTask。假设有多个线程执行若干任务,每个任务最多只能被执行一次。当多个线程试图同时执行同一个任务时,只允许一个线程执行任务,其他线程需要等待这个任务执行完后才能继续执行。下面是对应的示例代码。

private final ConcurrentMap<Object, Future<String>> taskCache = new ConcurrentHashMap<>();

    private String executionTask(final String taskName)throws ExecutionException, InterruptedException {
        while (true) {
            Future<String> future = taskCache.get(taskName); // 1.1,2.1
            if (future == null) {
                Callable<String> task = () -> taskName;
                FutureTask<String> futureTask = new FutureTask<>(task);
                future = taskCache.putIfAbsent(taskName, futureTask); // 1.3
                if (future == null) {
                    future = futureTask;
                    futureTask.run(); // 1.4执行任务
                }
            }
            try {
                return future.get(); // 1.5,
            } catch (CancellationException e) {
                taskCache.remove(taskName, future);
            }
        }
    }

public class ThreadTest {
    public static void main(String[] args){
        //使用FutureTask来包装Callable对象
        //使用Lambda表达式来创建Callable<Integer>对象
        FutureTask<Integer> task = new FutureTask<>(()->{
            System.out.println(Thread.currentThread().getName() + "   " + "开始执行任务!");
            return 0;
        });
        //实质还是以Callable对象来创建并启动线程
        //输出 新线程   开始执行任务!
        new Thread(task,"新线程").start();
        try{
            //获取线程的返回值
            //输出 0
            System.out.print(task.get());
        }catch (Exception ex){
            ex.printStackTrace();
        }

    }
}

 

FutureTask实现

jdk1.8的FutureTask有个说明:
修订说明:这与这个类以前依赖AbstractQueuedsynchronizer的版本不同,主要是为了避免在取消竞争期间保留中断状态让用户感到意外。在当前的设计中,Sync控件依赖于通过CAS更新的“state”字段来跟踪完成,以及一个简单的Treiber堆栈来保存等待的线程。
风格注意:与往常一样,我们绕过了使用 AtomicXFieldUpdaters的开销,而是直接使用Unsafe。

Future

FutureTask实现了Future接口,Future接口有5个方法:
1、boolean cancel(boolean mayInterruptIfRunning)
尝试取消当前任务的执行。如果任务已经取消、已经完成或者其他原因不能取消,尝试将失败。如果任务还没有启动就调用了cancel(true),任务将永远不会被执行。如果任务已经启动,参数mayInterruptIfRunning将决定任务是否应该中断执行该任务的线程,以尝试中断该任务。
如果任务不能被取消,通常是因为它已经正常完成,此时返回false,否则返回true
2、boolean isCancelled()
如果任务在正常结束之前被被取消返回true
3、boolean isDone()
正常结束、异常或者被取消导致任务完成,将返回true
4、V get()
等待任务结束,然后获取结果,如果任务在等待过程中被终端将抛出InterruptedException,如果任务被取消将抛出CancellationException,如果任务中执行过程中发生异常将抛出ExecutionException。
5、V get(long timeout, TimeUnit unit)
任务最多在给定时间内完成并返回结果,如果没有在给定时间内完成任务将抛出TimeoutException。

FutureTask状态转换

FutureTask有以下7中状态:
在这里插入图片描述
FutureTask任务的运行状态,最初为NEW。运行状态仅在set、setException和cancel方法中转换为终端状态。在完成过程中,状态可能呈现出瞬时值INTERRUPTING(仅在中断运行程序以满足cancel(true)的情况下)或者COMPLETING(在设置结果时)状态时。从这些中间状态到最终状态的转换使用成本更低的有序/延迟写,因为值是统一的,需要进一步修改。
state:表示当前任务的运行状态,FutureTask的所有方法都是围绕state开展的,state声明为volatile,保证了state的可见性,当对state进行修改时所有的线程都会看到。
NEW:表示一个新的任务,初始状态
COMPLETING:当任务被设置结果时,处于COMPLETING状态,这是一个中间状态。
NORMAL:表示任务正常结束。
EXCEPTIONAL:表示任务因异常而结束
CANCELLED:任务还未执行之前就调用了cancel(true)方法,任务处于CANCELLED
INTERRUPTING:当任务调用cancel(true)中断程序时,任务处于INTERRUPTING状态,这是一个中间状态。
INTERRUPTED:任务调用cancel(true)中断程序时会调用interrupt()方法中断线程运行,任务状态由INTERRUPTING转变为INTERRUPTED

可能的状态过渡:
 1、NEW -> COMPLETING -> NORMAL:正常结束
 2、NEW -> COMPLETING -> EXCEPTIONAL:异常结束
 3、NEW -> CANCELLED:任务被取消
 4、NEW -> INTERRUPTING -> INTERRUPTED:任务出现中断
FutureTask是Java中的一个类,用于表示一个异步计算的结果,它实现RunnableFuture接口。它的主要功能是对一个耗时的计算任务进行封装,该任务会在另一个线程中异步执行,并且可以获取到其执行结果。 FutureTask的使用非常简单,首先创建一个FutureTask对象,将需要执行的计算任务作为参数传入。然后可以通过调用FutureTask对象的get方法来获取计算结果,该方法会阻塞当前线程,直到计算任务完成并返回结果。另外,还可以通过调用FutureTask对象的cancel方法来取消计算任务的执行。 除了上述基本功能外,FutureTask还有一些其他的特性。例如,可以通过isDone方法来判断计算任务是否完成,通过isCancelled方法来判断计算任务是否被取消。另外,还可以通过传入Callable对象来创建FutureTask,这样可以更加灵活地指定计算任务。 FutureTask的一个常见应用场景是在多线程编程中,用于执行一些耗时的计算任务,而不阻塞主线程的执行。通过将计算任务封装为FutureTask,在主线程中可以继续执行其他操作,而不需要等待计算任务完成。当需要获取计算结果时,再通过调用FutureTask的get方法来获取结果,从而实现了异步计算和获取结果的功能。 总之,FutureTask是Java中用于表示异步计算结果的类,它提供了一些方法来控制和获取计算任务的结果,通过它可以实现多线程编程中的异步计算和获取结果的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值