6. Callable&Future 接口

6. Callable&Future 接口

6.1 Callable 接口

 通过Runable创建线程。但是,Runable缺少的一项功能是,当线程终止时(即 run() 完成时),我们无法是线程返回结果,为了支持此功能,Java提供了Callable接口。

  • 为了实现Runable,需要实现不返回任何内容的run() 方法,而对于Callable,需要实现在完成时返回结果的call()方法。请注意,不能使用Callable创建线程,只能使用Runable创建线程。
  • 另一个区别是call()方法可以引发异常,而run()则不能。
  • 为实现Callable而必须去重写call方法
public class CallableExample implements Callable {
    @Override
    public Object call() throws Exception {
        String uuid = UUID.randomUUID().toString();
        return uuid;
    }
}

6.2 Future 接口

 当call()方法完成是,结果必须存储在主线程已知对象中,以便主线程中可以知道

该线程返回的结果,为此,可以使用Future对象。将Future视为保存结果的对象-它可能暂时不保存结果,但将来会保存(一旦Callable返回)。

因此,Future基本上是主线程可以跟踪进度以及其他线程的结果的一个种方式。要实现此接口,必须重写5种方法,下面累出重要的方法。

/**
* 用于停止任务。
* 如果尚未启动,它将停止任务。如果已经启动,则仅在mayInterrupt为true时才会中断任
* 任务
*/
public boolean cancel(boolean mayInterruptIfRunning);

/**
* 抛出InterruptedException,ExecutionException
* 用于获取任务结果。如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回
* 结果。
*/
public V get();

/**
* 如果任务完成,则返回true,否则返回false
*
*/
public boolean isDone();

 可以看到Callable和Future做两件事情,Callable与Runable类似,因为它封装了要在另一个线程上运行的任务,而Future用于存储从另一个线程获取得的结果。实际上,future也可以与Runable一起使用。

 要创建线程,需要Runable。为了获得结果,需要future。

 Java库具有具体的FutureTask类型,该类型实现Runable和Future,并方便地将两种功能结合在一起。

 可以通过为其构造函数提供的Callable来创建FutureTask。然后将,FutureTask对象提供给Thread的构造函数以创建Thread对象,因此,间接使用Callable创建线程。

public class TestCallable implements Callable<Object> {
    private int taskNum;

    public TestCallable(int taskNum) {
        this.taskNum = taskNum;
    }

    private static void test() throws ExecutionException, InterruptedException {
        System.out.println("----程序开始运行----");
        Date date1 = new Date();
        int taskSize = 5;
        FutureTask[] randomNumberTasks = new FutureTask[5];
        List<Future> futureList = new ArrayList<>();
        for (int i = 0; i < taskSize; i++) {
            randomNumberTasks[i] = new FutureTask(new TestCallable(i));
            new Thread(randomNumberTasks[i]).start();
        }
        // 获取所有并发任务运行结果
        for (FutureTask randomNumberTask : randomNumberTasks) {
            System.out.println(">>>"+randomNumberTask.get().toString());
        }
        Date date2=new Date();
        System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");
    }

    @Override
    public Object call() throws Exception {
        System.out.println(">>>" + taskNum + "任务启动");
        Date dateTmpl = new Date();
        Thread.sleep(1000);
        Date dateTmpl2 = new Date();
        long time = dateTmpl2.getTime() - dateTmpl.getTime();
        System.out.println(">>>" + taskNum + "任务终止");
        return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test();
    }
}

结果:

----程序开始运行----
>>>2任务启动
>>>4任务启动
>>>0任务启动
>>>3任务启动
>>>1任务启动
>>>3任务终止
>>>4任务终止
>>>1任务终止
>>>2任务终止
>>>0任务终止
>>>0任务返回运行结果,当前任务时间【1013毫秒】
>>>1任务返回运行结果,当前任务时间【1012毫秒】
>>>2任务返回运行结果,当前任务时间【1013毫秒】
>>>3任务返回运行结果,当前任务时间【1013毫秒】
>>>4任务返回运行结果,当前任务时间【1013毫秒】
----程序结束运行----,程序运行时间【1014毫秒】

6.2 小结

 在主线程中需要执行比较耗操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,党主线程将来需要时,就可以通过Future对象获得后台作业计算结果或执行状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值