JUC高并发编程(11) -- Callable&Future接口

JUC高并发编程

七、Callable&Future接口

7.1)创建线程的方式

创建线程的方式有以下4种:

  1. 继承Thread类;

  2. 实现Runnable接口;

  3. 实现Callable接口;

  4. 调用线程池

Runnable接口缺少的一项功能是,当线程终止时(即run() 完成时),无法使线程返回结果,为了支持此功能, Java中提供了Callable接口。

7.2)Callable接口

Callable接口和Runnable接口相比较有以下特点:

  1. 为了实现Runnable需要实现不返回任何内容的run()方法,而对于 Callable,需要实现在完成时返回结果的call() 方法;

  2. call() 方法可以抛出异常,而run() 则不能抛出异常;

  3. 为实现Callable而必须重写call方法,不能直接替换Runnable,因为Thread类的构造方法根本没有Callable

    【解决该问题需要引入FutureTask,它和Runnable、Callable都有关联,Runnable接口有实现类FutureTask,FutureTask构造函数可以传递Callable】

Callable接口和Runnable接口代码如下:

//比较两个接口
//实现Runnable接口
class MyThread1 implements Runnable {
    @Override
    public void run() {
    // ...
    }
}
​
//实现Callable接口
class MyThread2 implements Callable {
​
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" come in callable");
        return 200;
    }
}

7.3)Future 接口

当 call() 方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。为此可以使用Future对象。

将Future视为保存结果的对象,它可能暂时不保存结果,但将来会保存(一旦 Callable返回)。

Future基本上是主线程可以跟踪进度以及其他线程的结果的一种方式;要实现此接口必须重写相关方法,这里列出了比较重要的方法,如下:

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

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

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

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

总结:要创建线程,需要Runnable/Callable;为了获得结果,需要future。

7.4)FutureTask

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

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

7.4.1)FutureTask核心原理

在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些任务交给Future对象在后台完成;

  • 当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态;

  • 一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果;

  • 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法 一旦计算完成,就不能再重新开始或取消计算 ;

  • get方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常;

  • get只计算一次,因此get方法放到最后执行。

7.4.2)FutureTask举例说明

例1:

老师上课口渴了,去买水不合适,讲课线程继续运行;

单开启线程让班长帮老师买水,把水买回来;

老师喝水时需要时候直接get水即可

例2:

3个同学计算, 1同学: 1+2...5 , 2同学:10+11+12....50, 3同学 100+200;

因为第2个同学计算量比较大,所以FutureTask单开启线程给2同学计算;

主线程先汇总1同学和3同学的计算结果 ,最后等2同学计算完成后,再统一汇总最终结果

核心思想:主线程中需要执行比较耗时的操作时,但又不想阻塞主线程,新增一个线程去处理耗时的操作,最终一次将所有操作汇总

7.5)Callable和Future代码示例

Callable 和 Future的代码示例如下:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //Runnable接口创建线程
        new Thread(new MyThread1(), "AA").start();
​
        //Callable接口,报错
        // new Thread(new MyThread2(),"BB").start();
​
        //FutureTask实现Callable接口
        FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
​
        //lam表达式:FutureTask实现Callable接口
        FutureTask<Integer> futureTask2 = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() + " come in callable");
            return 1024;
        });
​
        //创建一个线程
        new Thread(futureTask2, "lucy").start();
        new Thread(futureTask1, "mary").start();
​
        while(!futureTask2.isDone()) {
            System.out.println("futureTask2.isNotDone(),wait.....");
        }
​
        //调用FutureTask的get方法
        System.out.println(futureTask2.get());
​
        System.out.println(futureTask1.get());
​
        System.out.println(Thread.currentThread().getName() + " come over");
    }
}

输出:

futureTask2.isNotDone(),wait.....
futureTask2.isNotDone(),wait.....
...
futureTask2.isNotDone(),wait.....
mary come in callable
lucy come in callable
futureTask2.isNotDone(),wait.....
1024
200
main come over

7.6)小结

在主线程中需要执行比较耗时的操作,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成:

  • 当主线程将来需要时就可以通过Future 对象获得后台作业的计算结果或者执行状态 ;

  • 一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果;

  • 仅在计算完成时才能检索结果,如果计算尚未完成则阻塞 get 方法,一旦计算完成,就不能再重新开始或取消计算;

  • get方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常;

  • 只最终汇总计算一次。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值