JUC 走进Callable

简介: JUC 走进Callable

走进Callable

Callable接口类似于Runnable接口,因为他们都是为其实例可能由另一个线程执行的类执行设计的,然后Runnable接口既不抛出异常,也不返回结果(没有返回值)

    Runnable没有返回值,只能开辟不能接收

Callable总结有以下三种特点

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同,Runnable使用run(),Callable使用call()

查看源码可以发现Callable接口和Runnable接口一样也是一个函数式接口,可以使用lambda表达式它的泛型的参数等于返回值,也就是说,我们的参数声明什么格式,call()方法也返回什么样的格式


//源码
@FunctionalInterface  //函数式接口
public interface Callable<V> { //参数什么数据格式,方法返回什么数据格式
/**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
//代码举例 Object
class MyThread implements Callable<Object> {
    @Override
public Object call() throws Exception {
return null;
    }
}
//代码举例 integer
class MyThread implements Callable<Integer> {
    @Override
public Integer call() throws Exception {
return 1;
    }
} 
//代码举例 String
class MyThread implements Callable<String> {
    @Override
public String call() throws Exception {
return "1";
    }
}


image.png


问题:线程一般参数传的都是runnable进行启动(Thread中参数都是runnable),那么如何启动启动callable线程呢?

  1. 创建对应的线程类
  2. 通过FutureTask适配类 它的构造器就是callable接口 把callable线程类丢进去 可以把它想成中间商 用它来联系runnable
  3. 把futureTask丢进去然后就可以执行了
//线程启动的方式尤其只有一个 new Thread().start();
//怎么启动Callable接口线程? 由于Thread类的参数都是runnable类型的 和callable不匹配
//1 new Thread(new Runnable()).start()
//2 new Thread(new FutureTask<V>()).start()
//3 new Thread(new FutureTask<V>(Callable)).start()
//1 创建对应的线程类
MyThread myThread = new MyThread();
//2 通过FutureTask适配类 它的构造器就是callable接口 把callable线程类丢进去
FutureTask futureTask = new FutureTask<>(myThread);
//3 把futureTask丢进去然后就可以执行了
new Thread(futureTask, "线程A").start();


image.png


代码简单测试Callable接口


package com.wyh.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
 * @program: JUC
 * @description: callable接口简单测试 开启线程三种方式之一
 * @author: 魏一鹤
 * @createDate: 2022-02-17 21:15
 **/
//开启线程的三种方式 1继承Thread类 2实现Runnable接口 3实现Callable接口
public class CallableTest {
public static void main(String[] args){
        //线程启动的方式尤其只有一个 new Thread().start();
        //怎么启动Callable接口线程? 由于Thread类的参数都是runnable类型的 和callable不匹配
        //1 new Thread(new Runnable()).start()
        //2 new Thread(new FutureTask<V>()).start()
        //3 new Thread(new FutureTask<V>(Callable)).start()
        //实例化静态类
        MyThread myThread = new MyThread();
        //适配类 它的构造器就是callable接口  可以把它想成中间商 用它来联系runnable
        FutureTask futureTask = new FutureTask<>(myThread);
        //把futureTask丢进去然后就可以执行了
        new Thread(futureTask, "线程A").start();
    }
}
//静态资源线程类
class MyThread implements Callable<Integer> {
    @Override
public Integer call() throws Exception {
        System.out.println("进入call方法");
//程序员节 10.24
        return 1024;
    }
}


完善代码,接收返回值, 使用FutureTask适配器的get()方法接受callable接口的call方法的返回值,需要抛异常,一般返回Object类型,可以根据情况强行转换


package com.wyh.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 * @program: JUC
 * @description: callable接口简单测试 开启线程三种方式之一
 * @author: 魏一鹤
 * @createDate: 2022-02-17 21:15
 **/
//开启线程的三种方式 1继承Thread类 2实现Runnable接口 3实现Callable接口
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程启动的方式尤其只有一个 new Thread().start();
        //怎么启动Callable接口线程? 由于Thread类的参数都是runnable类型的 和callable不匹配
        //1 new Thread(new Runnable()).start()
        //2 new Thread(new FutureTask<V>()).start()
        //3 new Thread(new FutureTask<V>(Callable)).start()
        //实例化静态类
        MyThread myThread = new MyThread();
        //适配类 它的构造器就是callable接口 可以把它想成中间商 用它来联系runnable
        FutureTask futureTask = new FutureTask<>(myThread);
//把futureTask丢进去然后就可以执行了
        new Thread(futureTask, "线程A").start();
//使用futureTask适配器的get方法接收callable接口的返回值
        //需要抛异常
        //一般object就可以接受各种类型的返回值
        //Object o = futureTask.get();
        //因为call方法返回的是integer 这里从Object类型强行转换成Integer类型
        Integer o = (Integer) futureTask.get();
        System.out.println(o);
    }
}
//静态资源线程类
class MyThread implements Callable<Integer> {
    @Override
public Integer call() throws Exception {
        System.out.println("进入call方法");
//程序员节 10.24
        return 1024;
    }
}


进阶:可能出现的两个问题

问题1:get方法可能阻塞

解决:

1 get方法如果等待返回值时,方法耗时可能会产生阻塞会一直等,所以一般把获取返回结果(get方法)放到最后一行

2 或者通过异步通信(类似ajax)解决 让他先跑,他一边跑我一边执行,等他跑完了我再获取他的返回结果,不用刻意的等待


package com.wyh.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
 * @program: JUC
 * @description: callable接口简单测试 开启线程三种方式之一
 * @author: 魏一鹤
 * @createDate: 2022-02-17 21:15
 **/
//开启线程的三种方式 1继承Thread类 2实现Runnable接口 3实现Callable接口
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程启动的方式尤其只有一个 new Thread().start();
        //怎么启动Callable接口线程? 由于Thread类的参数都是runnable类型的 和callable不匹配
        //1 new Thread(new Runnable()).start()
        //2 new Thread(new FutureTask<V>()).start()
        //3 new Thread(new FutureTask<V>(Callable)).start()
        //实例化静态类
        MyThread myThread = new MyThread();
        //适配类 它的构造器就是callable接口  可以把它想成中间商 用它来联系runnable
        FutureTask futureTask = new FutureTask<>(myThread);
//把futureTask丢进去然后就可以执行了
        new Thread(futureTask, "线程A").start();
//使用futureTask适配器的get方法接收callable接口的返回值
        //需要抛异常
        //一般object就可以接受各种类型的返回值
        //Object o = futureTask.get();
        //因为call方法返回的是integer 这里从Object类型强行转换成Integer类型
        //get方法如果等待返回值时,方法耗时可能会产生阻塞会一直等,所以一般把获取返回结果(get方法)放到最后一行
        //或者通过异步通信(类似ajax)解决 让他先跑,他一边跑我一边执行,等他跑完了我再获取他的返回结果,不用刻意的等待
        Integer o = (Integer) futureTask.get();
        System.out.println(o);
    }
}
//静态资源线程类
class MyThread implements Callable<Integer> {
    @Override
public Integer call() throws Exception {
        //如果这是耗时操作 FutureTask适配器的get()方法就会一直等产生阻塞
        System.out.println("进入call方法");
//程序员节 10.24
        return 1024;
    }
}
目录
相关文章
|
6月前
|
Java
JAVA JUC Callable 接口
【1月更文挑战第5天】JAVA JUC Callable 接口
|
1月前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
32 0
|
3月前
|
缓存 Java
JUC(4)Callable和常用的辅助类
这篇文章介绍了Java并发工具包中的`Callable`接口及其与`Runnable`的区别,以及几个常用的并发辅助类,如`CountDownLatch`、`CyclicBarrier`和`Semaphore`,并提供了它们使用方式的示例代码。
|
6月前
|
Java 程序员
Java多线程基础-16:简述Java并发编程JUC中的Callable接口
Callable接口是Java中用于描述带有返回值任务的接口,与Runnable相对,后者无返回值。Callable的call()方法用于执行具体任务并返回结果。
83 0
|
监控 安全 Java
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
|
存储 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流 | 分支合并框架(一)
|
设计模式 缓存 Java
JUC并发编程学习(七)-Callable学习
JUC并发编程学习(七)-Callable学习
JUC并发编程学习(七)-Callable学习
|
SpringCloudAlibaba 前端开发 Java
JUC系列(四) callable与 常用的工具类
在多线程工作中常用的一些辅助类
JUC系列(四) callable与 常用的工具类