7_Callable&Future接口

Callable&Future接口

1、简介

  1. Runnable和Callable区别

    • Runnable无返回值,Callable可以使线程返回结果。
    • run()不会发生异常,call()方法可以引发异常
    • Callable不能直接替换 Runnable,因为 Thread 类的构造方法根本没有 Callable
  2. Future 接口

    //用于停止任务:如果尚未启动,它将停止任务。如果已启动,则仅 mayInterrupt 为 true 时才会中断任务。
    public boolean cancel(boolean mayInterrupt)
    //用于获取任务的结果。抛出 InterruptedException,ExecutionException
    //如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果
    public Object get()
    //如果任务完成,则返回 true,否则返回 false
    public boolean isDone()
    
  3. FutureTask

    • FutureTask实现了 Runnable 和 Future 接口
    • 使用 Callable 创建线程:①.为 FutureTask 构造函数提供 Callable对象, ②为Thread 构造函数提供 FutureTask 对象

2、代码

//Runnable创建线程
class MyThread1 implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程进入了 run 方法");
    }
}

//Callable创建线程
class MyThread2 implements Callable{
    @Override
    public Integer call(){
        System.out.println(Thread.currentThread().getName() + "线程进入了 call 方法");
        return 1234;
    }
}

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //Runnable接口
        new Thread(new MyThread1(),"AA").start();

        //Callable接口,报错,因为Thread对象只接受Runnable接口实现类。
//        new Thread(new MyThread2(),"BB").start();

       /*
       找一个类,既和Runnable有关系,又和Callable也有关系
       Runnable接口有实现类 FutureTask, FutureTask构造可以传递Callable
        */
        //FutureTask
        FutureTask<Integer> futureTask=new FutureTask<>(new MyThread2());

        //lambda表达式
        FutureTask<Integer> futureTask2=new FutureTask<>(()->{
            System.out.println(Thread.currentThread().getName() + "线程进入了 call 方法");
            return 1024;
        });

        new Thread(futureTask,"BB").start();

        //FutureTask 执行完之后可以随时获取到这个线程的返回值而不用再去执行一次(不用call了,直接用现成的结果)
        Integer integer = futureTask.get();
        System.out.println(integer);
        Integer integer2 = futureTask.get();
        System.out.println(integer2);
    }
}

3、总结

  1. 要创建线程,需要 Runnable。为了获得结果,需要 Future。
  2. 在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给 Future 对象在后台完成, 当主线程将来需要时,就可以通过 Future对象获得后台作业的计算结果或者执行状态
  3. 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果
  4. 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。get 方法获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。
  5. 只计算一次
上一篇:多线程的创建方式之Callable接口与线程池


下一篇:多线程的实现方式