JUC并发编程学习(七)-Callable学习

简介: JUC并发编程学习(七)-Callable学习

Callable

线程的创建方式主要有Thread、Runnable、Callable这几种,那么他们的主要区别是:

1.是否返回值?

Runnable无返回值,而Callable有返回值。

2.是否跑出异常?

Runnable无异常,Callable有异常

3.方法不同?

Runnable 运行的方法是run,Callable运行的方法是call

为了学习Callable,首先我们来写一个简单的线程,代码如下:

package com.jp.call;
import java.util.concurrent.Callable;
/**
 * @className:
 * @PackageName: com.jp.call
 * @author: youjp
 * @create: 2020-05-13 21:01
 * @description:   TODO 学习Callable
 * @Version: 1.0
 */
public class TestCallable {
    public static void main(String[] args) {
      //需要思考的地方
            new Thread(new Runnable() {
                @Override
                public void run() {
                }
            }).start();
    }
}
//自定义线程
class Mythread implements Callable{
    @Override
    public Object call() throws Exception {
        System.out.println("我是小Call我被调用了");
        return "小call";
    }
}

编写了一个有返回值的线程,但是我们要如何调用得到它呢?平时我们的线程大致的调用方法都是这种类型的:

20200401134307494.png

Thread与Callable之间的适配类:FutureTask

查看官方API文档里Thread的相关构造方法发现,Thread创建线程,只能与Runnable有联系,与Callable没有直接关系。

20200401134307494.png

Thread怎么创建Callable线程呢?

在设计模式中建立两者之间的关系经常使用适配器。什么是适配器呢?

适配器就是接口转换器。把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

我们去查找jdk官方文档,看能否找到Thread和Callable相互之间有关联的类。

1.查看Runnable官方文档

20200401134307494.png

2.查看Runnable的子类FutureTask

20200401134307494.png

可以看到通过FutureTask类我们找到了Thread与Callable之间联系了。

20200401134307494.png

FutureTask是一个异步运算的任务。FutureTask里面可以传入一个Callable的具体实现类,可以对这个异步运算的任务和结果进行等待、获取,并判断是否已经完成、取消任务等操作。由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中。

那么怎么使用呢?

package com.jp.call;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 * @className:
 * @PackageName: com.jp.call
 * @author: youjp
 * @create: 2020-05-13 21:01
 * @description:   TODO 学习Callable
 * @Version: 1.0
 */
public class TestCallable {
    public static void main(String[] args) {
        //适配类
        FutureTask futureTask=new FutureTask(new Mythread());
        //执行线程
        new Thread(futureTask).start();
        try {
            //获取返回值
            System.out.println("获取到返回值:"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
//自定义线程
class Mythread implements Callable{
    @Override
    public Object call() throws Exception {
        System.out.println("我是小Call我被调用了");
        return "小call";
    }
}

20200401134307494.png

Callable有什么优点

缓存: 结果缓存!效率提高N倍

结果获取会阻塞:task.get() 获取值的方法一般放到最后,保证程序平稳运行的效率,因为他会阻塞等待结果产生!

package com.jp.call;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
 * @className:
 * @PackageName: com.jp.call
 * @author: youjp
 * @create: 2020-05-13 21:01
 * @description:   TODO 学习Callable
 * @Version: 1.0
 */
public class TestCallable {
    public static void main(String[] args) {
        //适配类
        FutureTask futureTask=new FutureTask(new Mythread());
        //执行线程
        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start();
        try {
            //获取返回值
            System.out.println("获取到返回值:"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
//自定义线程
class Mythread implements Callable{
    @Override
    public Object call() throws Exception {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("我是小Call我被调用了");
        return "小call";
    }
}

运行结果如下:

20200401134307494.png

有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~


相关文章
|
3月前
|
Java
JAVA JUC Callable 接口
【1月更文挑战第5天】JAVA JUC Callable 接口
|
4天前
并发编程之Callable方法的详细解析(带小案例)
并发编程之Callable方法的详细解析(带小案例)
11 0
|
1月前
|
Java
Java并发编程:理解并使用Future和Callable接口
【2月更文挑战第25天】 在Java中,多线程编程是一个重要的概念,它允许我们同时执行多个任务。然而,有时候我们需要等待一个或多个线程完成,然后才能继续执行其他任务。这就需要使用到Future和Callable接口。本文将深入探讨这两个接口的用法,以及它们如何帮助我们更好地管理多线程。
|
5月前
|
存储 Java
并发编程系列教程(09) - Callable与Future模式
并发编程系列教程(09) - Callable与Future模式
25 0
|
6月前
|
监控 安全 Java
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
|
存储 Java
高并发编程之多线程锁和Callable&Future 接口
5 多线程锁 5.1 锁的八个问题演示 package com.xingchen.sync; import java.util.concurrent.TimeUnit; class Phone { public static synchronized void sendSMS() throws Exception { //停留4秒 TimeUnit.SECONDS.sleep(4); System.out.println("------sendSMS"); } public synchronized void
84 0
|
存储 Java
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(三)
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(一)
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(三)
|
存储 监控 安全
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(二)
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(二)
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(一)
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架
《JUC并发编程 - 基础篇》 Callable接口 | 辅助类 | 读写锁 | 阻塞队列 | 线程池 | Stream流 | 分支合并框架(一)
|
SpringCloudAlibaba 前端开发 Java
JUC系列(四) callable与 常用的工具类
在多线程工作中常用的一些辅助类
JUC系列(四) callable与 常用的工具类