并发编程之Callable方法的详细解析(带小案例)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 并发编程之Callable方法的详细解析(带小案例)

Callable

(第三种线程实现方式)

Callable与Runnable的区别

Callable与Runnable的区别

  1. 实现方法名称不一样
  2. 有返回值
  3. 抛出了异常



class Thread1 implements Runnable{
    @Override
    public void run() {
    }
}
class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        return null;
    }
}

Callable的使用

Callable线程类的运行,需要依靠FutureTask的封装,因为Thread类的构造方法只支持Runnable及其子类,于是就需要继承了Runnable的FutureTast来对Callable子类进行封装,下面是FurtureTast的继承关系源代码:

public class FutureTask<V> implements RunnableFuture<V> {

public interface RunnableFuture<V> extends Runnable, Future<V> {

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
    }
}
class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        System.out.println("come in");
        return 1024;
    }
}

Callable的细节

使用callable就相当于另外开了一条线程运行,调用get方法就相当于要获取这条线程的运行结果。

如果在mian线程中调用了get方法,就会阻塞起来等待这个线程的运行结果。

于是就出现如下情况:

demo1

运行结果:

代码:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println("main");
        System.out.println(futureTask.get()); //后调用get方法
    }
}
class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        System.out.println("come in");
        return 1024;
    }
}
demo2

运行结果:

代码:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread2());
        new Thread(futureTask).start();
        System.out.println(futureTask.get()); //先调用get方法,会在这里等待线程返回结果
        System.out.println("main");
    }
}
class Thread2 implements Callable<Integer>{
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        Thread.sleep(2000);
        System.out.println("come in");
        return 1024;
    }
}

Callable的细节2

callable多次运行,只会计算一次结果

运行结果:(可以看到 只执行了一次come in的输出,即call()这个方法的代码只运行了一次)

代码:



public class CallableDemo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Thread3());
        Thread t1 = new Thread(futureTask);  //第一次调用 这个 futruetask任务
        t1.start();
        Thread t2 = new Thread(futureTask);  //第二次调用 这个 futruetask任务
        t2.start();
        System.out.println(futureTask.get());
        System.out.println(futureTask.get());
        System.out.println("main");
    }
}
class Thread3 implements Callable<Integer>{
    private static int num = 0;
    //1.方法名称不一样  2.有返回值  3.抛出了异常
    @Override
    public Integer call() throws Exception {
        System.out.println("come in");
        return ++num;
    }
}

原生Thread多次执行start会抛出IllegalThreadStateException非法的线程状态异常,Callable也是一样

Thread的start() 源码:

public synchronized void start() {
     /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();  //如果线程已经启动,则抛出异常
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }


相关文章
|
9天前
|
人工智能
歌词结构的巧妙安排:写歌词的方法与技巧解析,妙笔生词AI智能写歌词软件
歌词创作是一门艺术,关键在于巧妙的结构安排。开头需迅速吸引听众,主体部分要坚实且富有逻辑,结尾则应留下深刻印象。《妙笔生词智能写歌词软件》提供多种 AI 功能,帮助创作者找到灵感,优化歌词结构,写出打动人心的作品。
|
15天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
35 3
|
10天前
|
人工智能
写歌词的技巧和方法全解析:开启你的音乐创作之旅,妙笔生词智能写歌词软件
怀揣音乐梦想,渴望用歌词抒发情感?掌握关键技巧,你也能踏上创作之旅。灵感来自生活点滴,主题明确,语言简洁,韵律和谐。借助“妙笔生词智能写歌词软件”,AI辅助创作,轻松写出动人歌词,实现音乐梦想。
|
1天前
|
机器学习/深度学习 人工智能 安全
TPAMI:安全强化学习方法、理论与应用综述,慕工大、同济、伯克利等深度解析
【10月更文挑战第27天】强化学习(RL)在实际应用中展现出巨大潜力,但其安全性问题日益凸显。为此,安全强化学习(SRL)应运而生。近日,来自慕尼黑工业大学、同济大学和加州大学伯克利分校的研究人员在《IEEE模式分析与机器智能汇刊》上发表了一篇综述论文,系统介绍了SRL的方法、理论和应用。SRL主要面临安全性定义模糊、探索与利用平衡以及鲁棒性与可靠性等挑战。研究人员提出了基于约束、基于风险和基于监督学习等多种方法来应对这些挑战。
9 2
|
6天前
|
Prometheus 监控 Cloud Native
实战经验:成功的DevOps实施案例解析
实战经验:成功的DevOps实施案例解析
21 6
|
9天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
11 1
|
16天前
|
存储 JavaScript 前端开发
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
68 2
|
16天前
|
SQL 监控 数据库
SQL语句是否都需要解析及其相关技巧和方法
在数据库管理中,SQL(结构化查询语言)语句的使用无处不在,它们负责数据的查询、插入、更新和删除等操作
|
16天前
|
SQL 数据可视化 BI
SQL语句及查询结果解析:技巧与方法
在数据库管理和数据分析中,SQL语句扮演着至关重要的角色
|
17天前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
23 0

推荐镜像

更多