线程等待/休眠/状态及 Runnable 和 Callable 的简单使用及原理

news2024/11/25 16:26:04

关于线程和进程的基本概念☛操作系统中线程和进程的概念理解 这篇文章已经有了很详细的解释, 接下来主要来讲讲线程等待与线程休眠 / 线程的几种状态 / Runnable 和 Callable 与 Thread 的概念和区别及 Executor 框架是什么样的.

关于线程

  • 1 线程等待与线程休眠
  • 2 线程一共有哪些状态
  • 3 Runnable() 接口实现多线程
  • 4 Callable 实现多线程
  • 5 Executor 框架

在学习下面的知识之前, 简单问一下 Thread 中的 run 和 start 的区别是什么?
在这里插入图片描述
其实 run 就是一个普通的方法, 并没有创建新的线程, 输出也是在原线程中执行的; 而 start 创建了一个新的线程, 在新的线程中执行输出.

1 线程等待与线程休眠

关于线程之间是并发执行的, 谁先执行谁后面执行程序员是无法感知的, 这都是由内核系统来进行控制, 也就是说我们创建了一个新的线程, 那么任务是让主线程执行还是新线程执行这是无法保证的, 虽然无法保证谁先去执行, 但是我们能控制哪个线程先结束, 哪个线程后结束, 这里就用到了 join 方法;

执行 join 方法的线程就会阻塞, 一直阻塞到对应的线程结束之后, 才会继续执行(如线程 A 调用了线程 B 的 join 方法, 此时 A 就会一直阻塞, 一直阻塞到 B 这个线程执行结束); 线程等待存在的意义就是为了控制线程结束的先后顺序.

关于线程休眠: 线程 A 调用了 sleep, A 就会被阻塞, 阻塞到 sleep 指定的时间.

2 线程一共有哪些状态

  • NEW: Thread 对象有了, 但是 PCB 还没有, 也就是任务安排了, 但是还没有开始执行;
  • RUNNABLE: 代表此线程正在 CPU 上执行或者是即将到 CPU 上执行, PCB 在就绪队列中, 随时可能被调度到;
  • WAITING: wait 方法(当操作条件不成熟就等待, 操作流程: 释放锁->等待通知->收到通知后重新获取锁->继续往下执行, wait 方法必须在 synchronized 代码块内部使用)导致的, 此线程暂时停了下来, 不会继续到 CPU 上执行, 等时机成熟后才有机会再去执行;
  • TIMED_WAITING: sleep 方法导致的;
  • BLOCKED: 等待锁导致的;
  • TERMINATED: 内核中的线程已经结束了, 也就是 PCB 没了, 但是代码中的 Thread 对象还在, 这时候就等着 GC 来回收吧.

3 Runnable() 接口实现多线程

Thread 的核心功能就是进行线程的启动, 如果一个类为了实现多线程而去直接继承 Thread 类就会出现单继承的局限问题, 因此 java 中又提供了另外的实现模式, 使用 Runnable 接口去实现多线程;

static class Thread1 implements Runnable {
        private String str;

        public Thread1(String str) {
            this.str = str;
        }

        @Override
        public void run() {
            for (int i = 0; i < 2; i++) {
                System.out.println(this.str + ",i = " + i);
            }
        }
    }

    public static void main(String[] args) {
        Thread1 t1 = new Thread1("t1");
        Thread1 t2 = new Thread1("t2");
        Thread1 t3 = new Thread1("t3");
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
    }

如上代码就是通过 Runnable 接口来实现多线程的例子, 因为 Thread1 类中不是 Thread 类实现的, 因此没有了 start 方法, 所以 main 方法启动这三个线程的时候我又使用 Thread 提供的构造方法; 当然这里也可以直接写成 Thread t1 = new Thread(new Thread1) 这种形式.

运行结果:
在这里插入图片描述
这里需要注意, 所线程的启动永远都是 Thread 类的 start() 方法.

关于 Thread 和 Runnable 的区别:

  • 首先从使用形式来看, Runnable 实现多线程可以避免单继承的局限问题;
  • 其实 Thread 类是 Runnable 接口的子类, 并且 Thread 类覆写了 Runnable 接口的 run() 方法;
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
  • Runnable 实现的多线程的程序类可以更好的描述出程序共享的概念.

4 Callable 实现多线程

在这里插入图片描述

static class Thread2 implements Callable<String> {
        private int num = 3;

        @Override
        public String call() throws Exception {
            while (num > 0) {
                System.out.println("num = " + num--);
            }
            return "打印完成";
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<>(new Thread2());
        new Thread(task).start();
        System.out.println(task.get());
    }

运行结果:
在这里插入图片描述

  • Runnable 的 run() 方法没有返回值, 其设计遵循了主方法的设计原则, 也就是线程开始了就别想回头, 但是很多时候我们需要用到一些返回值, 例如某些线程执行完成后可能带来的一些返回结果, 这种情况下就只能使用 Callable 来实现多线程了.
  • 当然这种情况多线程的启动还是只有 Thread 类中的 start() 方法可以实现.

关于 Runnable 和 Callable 之间的区别:

  • Runnable 指的是一个对象能够被执行, 而 Callable 则是针对一个函数或者一个方法能够被调用;
  • Runnable 通过实现接口中的 run() 方法来定义可执行代码, 而 Callable 则是通过实现接口中的 call() 方法来定义可调用的代码;
  • Runnable 可以通过创建线程来执行, 而 Callable 则是通过作为 FeatureTask 的参数来使用的.

5 Executor 框架

Java 线程启动时会创建一个本地操作系统线程, 当线程终止时, 本地操作系统线程也会被回收, 并且操作系统会调度所有线程并将它们分配给可用的 CPU.
在这里插入图片描述

在上层, Java 多线程程序通常会把应用分割成若干个任务, 然后使用调度器 (Executor 框架) 将这些任务映射到固定数量的线程; 在底层, 操作系统内核将这些线程映射到硬件处理器上.

Executor 框架最核心的类就是 ThreadPoolExecutor, 也是线程池的实现类, 通过 Executor 框架的工具类 Executors, 可以创建三种类型的 ThreadPoolExecutor:

  • public static ExecutorService new CachedThreadPool(): 创建无大小限制的线程池;
  • public static ExecutorService new FixedThreadPool(int nThreads): 创建固定大小的线程池;
  • public static ExecutorService newSingleThreadExeeeeeecutor(): 单线程池.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[洛谷-P3698][CQOI2017]小Q的棋盘

一、问题 题目描述 小 Q 正在设计一种棋类游戏。 在小 Q 设计的游戏中&#xff0c;棋子可以放在棋盘上的格点中。某些格点之间有连线&#xff0c;棋子只能在有连线的格点之间移动。整个棋盘上共有 VVV 个格点&#xff0c;编号为 0,1,2,⋯,V−10,1,2,\cdots, V- 10,1,2,⋯,V−…

【C++知识点】C++11 常用新特性总结

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;C/C知识点 &#x1f4e3;专栏定位&#xff1a;整理一下 C 相关的知识点&#xff0c;供大家学习参考~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;…

EasyRcovery16免费的电脑照片数据恢复软件

电脑作为一种重要的数据储存设备&#xff0c;其中保存着大量的文档&#xff0c;邮件&#xff0c;视频&#xff0c;音频和照片。那么&#xff0c;如果电脑照片被删除了怎么办&#xff1f;今天小编给大家介绍&#xff0c;误删除的照片从哪里可以找回来&#xff0c;误删除的照片如…

win10打印机拒绝访问解决方法

一直以来,在安装使用共享打印机打印一些文件的时候&#xff0c;会遇到错误提示&#xff1a;“无法访问.你可能没有权限使用网络资源。请与这台服务器的管理员联系”的问题&#xff0c;那为什么共享打印机拒绝访问呢&#xff1f;别着急&#xff0c;下面为大家带来相关的解决方法…

mysql时区问题

设置mysql容器时间与服务器时间一致 问题背景&#xff1a; 今天测试发现一个问题&#xff0c;时间不一致&#xff0c;当工单入库时&#xff0c;其创建时间和更新时间应该是一样的&#xff0c;即使不一样最多只会错几秒的时间&#xff1b;实际上两个时间相差的大概8小时&#…

青少年学AI,Amazon DeepRacer有何魔力?

导读&#xff1a;北京名校中学生可以根据兴趣开发AI模型甚至发表论文&#xff0c;偏远地区的校长还在犹豫“人工智能教育&#xff0c;中考会考吗&#xff1f;高考会加分吗&#xff1f;”教育鸿沟由来已久&#xff0c;绝非仅靠某些企业或教育机构可以扭转&#xff0c;但我们至少…

maven仓库的配置

下载 官网下载&#xff1a;https://maven.apache.org/download.cgi 2. 配置maven环境 右键电脑 ->属性 -> 高级系统设置 -> 环境变量 -> 系统变量-新建 变量名&#xff1a;MAVEN_HOME 变量值为maven的文件安装地址 编辑Path系统变量 新建&#xff1a;%MAVE…

132.《render-props, Hoc,自定义hooks 详解》

文章目录render-props 模式props 方式children 方式(推荐)Hoc&#xff08;高阶组件&#xff09;使用步骤示例props 丢失解决方案自定义 hook1.只执行一次2.防抖hook高阶组件与自定义hook有什么区别相同点不同点React 中代码逻辑复用有三种方式&#xff0c;render-props, Hoc&am…

Altium Designer(AD)软件使用记录05-PCB叠层设计

目录Altium Designer(AD)软件使用记录05-PCB叠层设计一、正片层和负片层的介绍1、正片层(Signal)2、负片层(Plane)3、内电层的分割实现二、正片层和负片层的内缩设计1、负片设置内缩20H原则2、正片铺铜设置内缩1、设置规则2、重新铺铜三、AD的层叠设计四、叠层设计需要注意的问…

计算机组成原理_总线标准

计算机组成原理总目录总线标准 总线标准是系统与各模块、模块与模块之间的一个互连的标准&#xff0c;就像我们用汉语来相互交流一样。 1. 系统总线 ISA总线的扩展插槽&#xff0c;其颜色一般为黑色&#xff0c;比PCI接口插槽要长些&#xff0c;位于主板的最下端。 可插接显卡&…

Java中的深克隆与浅克隆

浅克隆&#xff1a; 实现Cloneable接口即可实现&#xff0c;浅克隆只对象内部的基础数据类型&#xff08;包括包装类&#xff09;被克隆&#xff0c;引用数据类型&#xff08;负责对象&#xff09;会被使用引用的方式传递。 简单来说&#xff0c;就是浅克隆属性如果是复杂对象…

java多线程(二五)ReentrantReadWriteLock读写锁详解(1)

一、读写锁简介 现实中有这样一种场景&#xff1a;对共享资源有读和写的操作&#xff0c;且写操作没有读操作那么频繁。在没有写操作的时候&#xff0c;多个线程同时读一个资源没有任何问题&#xff0c;所以应该允许多个线程同时读取共享资源&#xff1b;但是如果一个线程想去…

有关3dmax对齐技巧的那些事

建模操作中&#xff0c;对齐是非常常用的一个功能&#xff0c;用好这个对齐功能能够事半功倍&#xff0c;好处我不说了&#xff0c;下面我们这篇博文就来说说3dmax对齐技巧的相关的内容。 文章目录一、点对齐1、样条线中的点对齐2、多边形中的点对齐二、线对齐三、面对齐四、物…

DJI ROS dji_sdk 源码分析|整体框架

DJI ROS dji_sdk 源码分析|整体框架launch文件CMakeLists.txtcpp文件main.cppOSDK 是一个用于开发无人机应用程序的开发工具包&#xff0c;基于OSDK 开发的应用程序能够运行在机载计算机上&#xff08;如Manifold 2&#xff09;&#xff0c;开发者通过调用OSDK 中指定的接口能够…

计算机网络考研-第一章学

计算机网学习总结第一章计算机系统概述1.1.1 导学1.1.2 操作系统的特征1.2 操作系统的发展与分类1.3 操作系统的运行环境1.3.1 操作系统的运行机制1.3.2 中断和异常1.3.3系统调用&#xff1a;1.3.4 操作系统的体系结构第一章总结第一章计算机系统概述 1.1.1 导学 1.1.2 操作系…

Nginx 配置实例-反向代理案例一

实现效果&#xff1a;使用nginx反向代理&#xff0c;访问 www.suke.com 直接跳转到本机地址127.0.0.1:8080 一、准备工作 Centos7 安装 Nginxhttps://liush.blog.csdn.net/article/details/125027693 1. 启动一个 tomcat Centos7安装JDK1.8https://liush.blog.csdn.net/arti…

简单粗暴的分布式定时任务解决方案

分布式定时任务1.为什么需要定时任务&#xff1f;2.数据库实现分布式定时任务3.基于redis实现1.为什么需要定时任务&#xff1f; 因为有时候我们需要定时的执行一些操作&#xff0c;比如业务中产生的一些临时文件&#xff0c;临时文件不能立即删除&#xff0c;因为不清楚用户是…

基于FPGA实现正弦插值算法

1、正弦插值的算法分析 1.1 信号在时域与频域的映射关系 在进行正弦算法分析之前&#xff0c;我们回顾一下《数字信号处理》课程中&#xff0c;对于信号在时域与频域之间的映射关系&#xff0c;如下图。 对于上图中的原始信号x(t)&#xff0c;使用ADC对信号进行采样&#xff0…

【操作系统】进程句柄

进程句柄句柄是什么为什么需要句柄作用句柄是什么 先给结论&#xff0c;句柄&#xff08;handle&#xff09;实际上是一个指向指针的指针。 它指向进程所要访问的进程对象的地址&#xff0c;是用来找到目标进程的索引&#xff0c;当我们想要访问对象进程时&#xff0c;就要利…

从一道面试题看 TCP 的吞吐极限

分享一个 TCP 面试题&#xff1a;单条 TCP 流如何打满香港到旧金山的 320Gbps 专线&#xff1f;(补充&#xff0c;写成 400Gbps 更具迷惑性&#xff0c;但预测大多数人都会跑偏&#xff0c;320Gbps 也就白给了) 这个题目是上周帮一个朋友想的&#xff0c;建议他别问三次握手&a…