Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >(八)Callable和Runnable的区别

(八)Callable和Runnable的区别

作者头像
HaC
发布于 2020-12-30 09:57:07
发布于 2020-12-30 09:57:07
45900
代码可运行
举报
文章被收录于专栏:HaC的技术专栏HaC的技术专栏
运行总次数:0
代码可运行

Callable和Runnable都是一个接口。

Runnable

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

Runnable只有一个run方法,在使用普通线程的时候,我们可以实现Runnable接口即可,Thread类在调用start()函数后就是执行的是Runnable的run()函数。

简单使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 Thread thread =new Thread(new TestRunnable());
 thread.start();

Runnable的run方法没有返回值。

demo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ThreadPoolALL {
    public static void main(String[] args) {
        new ThreadPoolALL().ExecutorThreadPool();
    }

    static class TestRunnable implements Runnable {
        static int i = 0;

        @Override
        public void run() {
           //加锁顺序执行
          synchronized (this){
              int count = getCount();
              System.out.println(Thread.currentThread().getName() + "  线程被调用了。第" + count + "次");
              if (count == 10) {
                  throw new RuntimeException("Runnable 任务出错了");
              }
          }

        }

        public static int getCount() {
            return ++i;
        }
    }
    public void ExecutorThreadPool() {
        //自定义线程池
        int corePoolSize = 2; //线程池维护线程的最少数量
        int maxPoolSize = 3; //线程池维护线程的最大数量
        long keepAliveTime = 60; //线程池维护线程所允许的空闲时间(解释:当线程池的数量超过corePoolSize时,多余的空闲线程的存活时间。)
        RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
        BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>(10);
        //或者
        ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                SecurityManager s = System.getSecurityManager();
                ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
                Thread t = new Thread(group, r);
                //设置优先级
                if (t.getPriority() != Thread.NORM_PRIORITY) {
                    t.setPriority(Thread.NORM_PRIORITY);
                }
                //设置错误处理
                t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        //自定义处理错误
                        System.out.println("factory捕获了错误--->>>" + t.getName() + e);
                    }
                });
                return t;
            }
        };

        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, factory, rejectedExecutionHandler);


        TestRunnable testRunnable = new TestRunnable();

        for (int i = 0; i < 10; i++) {
            executor.execute(testRunnable);
        }
    }
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Thread-0  线程被调用了。第1次
Thread-1  线程被调用了。第2次
Thread-0  线程被调用了。第3次
Thread-1  线程被调用了。第4次
Thread-0  线程被调用了。第5次
Thread-0  线程被调用了。第6次
Thread-0  线程被调用了。第7次
Thread-0  线程被调用了。第8次
Thread-0  线程被调用了。第9次
Thread-1  线程被调用了。第10次
factory捕获了错误--->>>Thread-1java.lang.RuntimeException: Runnable 任务出错了

可以看到factory可以自定义使用自己的异常捕获方法。

Callable

Callable和Runnable最大的区别就是它的call方法有一个返回值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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;
}

说到返回值,又不得不提 Future。

Future就是对于具体Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作,其中get()方法会阻塞,所以通过get()方法可以判断线程是否执行完毕。

在Future接口中声明了5个方法,下面依次解释每个方法的作用:

  • cancel()方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
  • isCancelled()方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  • isDone()方法表示任务是否已经完成,若任务完成,则返回true;
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

也就是说Future提供了三种功能:

1)判断任务是否完成;

2)能够中断任务;

3)能够获取任务执行结果。

demo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ThreadPoolALL2 {
    public static void main(String[] args) {
        new ThreadPoolALL2().ExecutorThreadPool();
    }

     static class TestCallable implements Callable<String> {
        static int i = 0;

        public static int getCount() {
            return ++i;
        }

        //可定义回参类型
        @Override
        public String call() {
            int count = getCount();
            System.out.println(Thread.currentThread().getName() + "  线程被调用了。第" + count + "次");
            if (count == 2) {
                throw new RuntimeException("Callable 任务出错了");
            }
            return "finish";
        }
    }
    
    public void ExecutorThreadPool() {
        //自定义线程池
        int corePoolSize = 2; //线程池维护线程的最少数量
        int maxPoolSize = 3; //线程池维护线程的最大数量
        long keepAliveTime = 60; //线程池维护线程所允许的空闲时间(解释:当线程池的数量超过corePoolSize时,多余的空闲线程的存活时间。)
        RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
        BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>(10);
        //或者
        ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                SecurityManager s = System.getSecurityManager();
                ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
                Thread t = new Thread(group, r);
                //设置优先级
                if (t.getPriority() != Thread.NORM_PRIORITY) {
                    t.setPriority(Thread.NORM_PRIORITY);
                }
                //设置错误处理
                t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        //自定义处理错误
                        System.out.println("factory捕获了错误--->>>" + t.getName() + e);
                    }
                });
                return t;
            }
        };

        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, factory, rejectedExecutionHandler);


        TestCallable testCallable = new TestCallable();
        for (int i = 0; i < 2; i++) {
            Future<String> future = executor.submit(testCallable);
            try {
                future.get();
                String s = future.get();
                if ("finish".equals(s)) {
                    System.out.println("future.isDone()的值:" + future.isDone() + ",经过返回值比较,submit方法执行任务成功,当前线程名称--->>>" + Thread.currentThread().getName());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
    }
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Thread-0  线程被调用了。第1次
future.isDone()的值:true,经过返回值比较,submit方法执行任务成功,当前线程名称--->>>main
Thread-2  线程被调用了。第2次
java.util.concurrent.ExecutionException: java.lang.RuntimeException: Callable 任务出错了
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at com.yudianxx.basic.线程.Executor.ThreadPoolALL.ExecutorThreadPool(ThreadPoolALL.java:116)
	at com.yudianxx.basic.线程.Executor.ThreadPoolALL.main(ThreadPoolALL.java:12)
Caused by: java.lang.RuntimeException: Callable 任务出错了
	at com.yudianxx.basic.线程.Executor.ThreadPoolALL$TestCallable.call(ThreadPoolALL.java:48)
	at com.yudianxx.basic.线程.Executor.ThreadPoolALL$TestCallable.call(ThreadPoolALL.java:35)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)

可以看到:

这个异常将被Future.get封装在ExecutionException中重新抛出。

所以,无论是抛出的未检查异常还是已检查异常,都将被认为是任务返回状态的一部分,因此不会交由异常处理器来处理,我们就不需要使用ThreadFactory去处理异常了。

  1. 通过 feture.get() 的方法,一个线程结束后,就会空闲,所以虽然 corePoolSize+workQueue>=maximumPoolSize ,但也不会走拒绝策略。

以上结论:

  1. 通过execute方式提交的任务,能将它抛出的异常交给异常处理器。
  2. 通过submit方式提交任务,则异常不能被异常处理器捕获。

submit 和 execute的区别

  1. execute执行的是一个Runnable任务,submit 执行 Runnable和Callable都可以。
  2. execute的提交没有返回值,而submit的提交会返回一个Future类型的对象
  3. execute提交的时候,如果有异常,就会直接抛出异常;而submit在遇到异常的时候,通常不会立马抛出异常,而是会将异常暂时存储起来,等待你调用Future.get()方法的时候,才会抛出异常。

总结

  1. Runnable可以提交给Thread,直接启动一个线程来执行。核心方法是run(),通过excuse()方法执行。
  2. Callable一般都是提交给ExecuteService来执行,核心方法是call(),通过submit方法执行。
  3. Runnable执行没有返回;Callable有返回。

参考:

详解线程池execute和submit用法:

https://www.cnblogs.com/by-my-blog/p/10779333.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Yolov8 源码解析(四十三)
ApacheCN_飞龙
2024/09/13
2960
Yolov8 源码解析(四十)
ApacheCN_飞龙
2024/09/13
3760
Yolov8 源码解析(四十二)
ApacheCN_飞龙
2024/09/13
3980
Yolov8 源码解析(四十四)
ApacheCN_飞龙
2024/09/13
2970
30分钟吃掉YOLOv8实例分割范例
本范例我们使用 torchkeras来实现对 ultralytics中的YOLOv8实例分割模型进行自定义的训练,从而对气球进行检测和分割。
lyhue1991
2023/09/17
2.6K1
30分钟吃掉YOLOv8实例分割范例
YOLOv8 训练自己的数据集
本范例我们使用 ultralytics中的YOLOv8目标检测模型训练自己的数据集,从而能够检测气球。
lyhue1991
2023/09/05
3.4K1
YOLOv8 训练自己的数据集
【目标检测】YOLOv5-5.0增加save_crop及后处理
因为项目中用到的是YOLOv5-5.0版本,save_crop是6.0版本才开始有的接口,因此需要将6.0版本做一个迁移。 此篇博文主要用作代码备份,自用为主。
zstar
2022/10/28
1.4K0
深度好文 | YOLOv5+DeepSORT多目标跟踪深入解读与测试(含源码)
本文主要介绍如何使用Yolo-V5 + DeepSORT实现多目标检测与跟踪。(公众号:OpenCV与AI深度学习)
Color Space
2022/09/26
12.8K0
YoloV8自定义姿势关键点检测教程:机械臂关键点姿势跟踪(步骤 + 源码)
自定义姿势关键点检测是一种计算机视觉技术,涉及识别和跟踪对象上的特定点或关键点。对于下棋机器人手臂来说,这些关键点可以代表棋子的位置、棋盘的方向,甚至机器人手臂本身的配置。
Color Space
2024/01/12
1.8K0
YoloV8自定义姿势关键点检测教程:机械臂关键点姿势跟踪(步骤 + 源码)
使用YOLOv8和ByteTracker进行实时人员跟踪和计数
在计算机视觉领域,实时跟踪和统计人数对于各种应用至关重要,从监控到事件管理。在这篇博客文章中,我们将探讨如何利用YOLOv8和ByteTracker实现准确的人数统计。
小白学视觉
2025/01/15
2520
使用YOLOv8和ByteTracker进行实时人员跟踪和计数
实战 | 使用YOLOv8 Pose实现瑜伽姿势识别
瑜伽是一种古老的运动,近年来由于其对身心健康的众多益处而广受欢迎。随着人们对瑜伽的兴趣日益浓厚,对能够准确分类瑜伽姿势的自动化系统的需求也越来越大。本文中我们将探讨如何使用 YOLOv8 Pose(一种先进的对象检测模型)对图像和视频中的瑜伽姿势进行分类。
Color Space
2024/04/19
2.2K0
实战 | 使用YOLOv8 Pose实现瑜伽姿势识别
基于YOLOv8的老虎姿态(Tiger-Pose)识别
💡💡💡本文解决什么问题:教会你如何用自己的数据集训练Yolov8-pose关键点检测
AI小怪兽
2024/01/13
1.5K2
全球人工智能技术创新大赛【热身赛一】布匹疵点智能识别Baseline
在布匹的实际生产过程中,由于各方面因素的影响,会产生污渍、破洞、毛粒等瑕疵,为保证产品质量,需要对布匹进行瑕疵检测。布匹疵点检验是纺织行业生产和质量管理的重要环节,目前人工检测易受主观因素影响,缺乏一致性;并且检测人员在强光下长时间工作对视力影响极大。由于布匹疵点种类繁多、形态变化多样、观察识别难道大,导致布匹疵点智能检测是困扰行业多年的技术瓶颈。
听城
2021/03/02
1.5K0
全球人工智能技术创新大赛【热身赛一】布匹疵点智能识别Baseline
基于YOLOv8的遥感SAR舰船小目标识别
本文摘要:基于YOLOv8的遥感SAR舰船小目标,阐述了整个数据制作和训练可视化过程
AI小怪兽
2024/01/12
1.5K2
使用OpenCV和YOLOv8制作目标检测器(附源码)
YOLO(You Only Look Once)是由Joseph Redmon和Ali开发的一种对象检测和图像分割模型。
小F
2023/09/19
3.1K1
使用OpenCV和YOLOv8制作目标检测器(附源码)
【图像分类】YOLOv5-6.2全新版本:支持图像分类
众所周知,YOLOv5是一款优秀的目标检测模型,但实际上,它也支持图像分类。在6.1版本中,就暗留了classify这个参数,可以在做检测的同时进行分类。
zstar
2022/09/23
1.9K0
【图像分类】YOLOv5-6.2全新版本:支持图像分类
微调YOLOv11:实用指南 【详细过程与代码】
本指南旨在引导您为自身任务微调YOLOv11。我将分享我个人认为有效的步骤,附带详细代码、真实案例及实用建议。内容包括:
小白学视觉
2025/01/07
1.4K0
微调YOLOv11:实用指南 【详细过程与代码】
Google Colab上的YOLOv3 PyTorch
对于计算机视觉爱好者来说,YOLO(一次只看一次)是一种非常流行的实时对象检测概念,因为它的速度非常快并且性能出色。
代码医生工作室
2020/04/14
2.8K0
Google Colab上的YOLOv3 PyTorch
基于YOLOv8的晶体管定位识别(pose),从数据集标注到训练手把手教程
💡💡💡本文解决什么问题:教会你如何用晶体管从标注到训练Yolov8-pose关键点检测
AI小怪兽
2024/01/22
2K4
手把手入门教程:YOLOv8如何训练自己的数据集,交通信号灯识别
Ultralytics YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本。YOLOv8是一种尖端的、最先进的(SOTA)模型,它建立在先前YOLO成功基础上,并引入了新功能和改进,以进一步提升性能和灵活性。它可以在大型数据集上进行训练,并且能够在各种硬件平台上运行,从CPU到GPU。
AI小怪兽
2023/11/03
7.6K0
推荐阅读
相关推荐
Yolov8 源码解析(四十三)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验