当前位置: 首页 > news >正文

JavaEE之多线程(创建线程的五种写法)详解

😽博主CSDN主页: 小源_😽

🖋️个人专栏: JavaEE

😀努力追逐大佬们的步伐~


目录

1. 前言 

2. 操作系统"内核"

3. 创建线程的五种写法 (我们重点要掌握最后一种写法!!)

3.1 继承 Thread, 重写 run

3. 2 实现 Runnable 接口, 重写 run

3.3 继承 Thread, 重写 run, 使用匿名内部类

3.4 实现 Runnable, 重写 run, 使用匿名内部类

3.5  [常用/推荐] 使用 lambda 表达式

4. 小结


1. 前言 

我们在写代码的时候, 可以使用多进程进行并发编程, 也可以使用多线程并发编程.

但是多进程并发编程在 Java 中不太推荐, 因为很多和多进程编程相关的 api 在 Java 标准库中都没有提供, 并且在上篇文章中我们讲解了多线程并发编程时效率更高(在需要频繁创建和销毁进程的时候), 并且对于 Java 进程, 需要启动 Java 虚拟机, 导致开销更大 (搞多个 Java 进程就是搞多个 Java 虚拟机)

系统提供了多线程编程的 api, Java 标准库中把这些 api 封装了, 在代码中可以直接使用. 我们重点学习 Thread 这样的类

本章重点

本文着重讲解了创建线程的五种写法


2. 操作系统"内核"

我们在学习创建线程之前, 需要先了解操作系统"内核", 它是操作系统中最核心的模块 (用来管理与硬件和给软件提供稳定的运行环境)

操作系统有两个状态: 内核态和用户态, 并且各有自己的空间 (内核空间, 用户空间)

比如我们平时运行的普通的应用程序 (如 idea, java, 画图板, qq音乐......) 都是运行在用户态的, 当操作这些从程序时, 不是应用程序直接操作的, 而是需要调用系统的 api, 在内核中完成操作

为什么要划分出这两个状态呢??

最主要的目的是为了 "稳定": 防止你的应用程序破坏硬件设备或者软件资源

系统封装了一些 api, 这些 api 都是一些合法的操作, 应用程序只能调用这些 api, 就不至于对系统火与硬件设备产生危害 (如果应用程序可以直接操作硬件, 极端情况下, 代码出现 bug, 可能把硬件烧坏)


3. 创建线程的五种写法 (我们重点要掌握最后一种写法!!)

每个线程都是一个独立的执行流, 每个线程都能够独立的去 cpu 上调度执行

3.1 继承 Thread, 重写 run

  1. 创建一个自己的类, 继承自这个 Thread
  2. 根据刚才的类, 创建出实例
  3. 调用 Thread 的 start 方法 
package thread;// 1. 创建一个自己的类, 继承自这个 Thread// 这个 Thread 类能直接使用, 不需要导入包, 是因为 Java 标准库中, 有一个特殊的包 java.long, 和 String 类似 (也在 java.long 包中)
class MyThread extends Thread {// 这里重写的 run 入口方法必须手动指定, 针对原有的 Thread 进行扩展 (把一些能复用的复用, 需要扩展的扩展)@Overridepublic void run() {// run 方法就是该线程的入口方法. 和 main 方法类似, main 方法是一个进程的入口方法 (也可以说 main 方法是主线程的入口方法)// 一个进程至少有一个线程, 这个进程中的第一个线程就叫做"主线程", 如果一个进程只有一个线程, 即 main 线程就是主线程System.out.println("hello world");}
}public class ThreadDemo1 {public static void main(String[] args) {// 2. 根据刚才的类, 创建出实例. (线程实例,才是真正的线程).MyThread t = new MyThread();// Thread t = new MyThread();// 3. 调用 Thread 的 start 方法, 才会真正调用系统的 api, 在系统内核中创建出线程, 然后线程就会执行上面的 run 方法了t.start();}
}

按照之前的理解 (没有学习多线程之前), 如果一个代码出现了死循环, 最多只能执行一个, 另一个循环是进不去的, 下面我们来创建两个线程

package thread;class MyThread2 extends Thread {@Overridepublic void run() {while (true) {System.out.println("hello thread");// (我们使用的 sleep 是 Java 中封装后的版本, 是 Thread 提供的静态方法) 加 sleep 来降低循环的速度 (这里让 t 线程睡眠 1s (1000ms 等于 1s)), 先写第 19 行代码把鼠标指针放在 sleep 上, 按 Alt + Enter 即可try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}public class ThreadDemo2 {public static void main(String[] args) {Thread t = new MyThread2();t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

两个线程都在执行, 互不干扰, 运行结果为: 

我们可以发现:  每一秒打印的顺序都是随机的, 这里涉及到一个重要结论, 当一个进程中有多个线程时, 这些线程执行的先后顺序, 是完全随机的. (因为操作系统内核中, 有一个"调度器" 模块, 这个模块的实现方式类似 "随机调度" 的效果)

什么是"随机调度"

  1. 一个进程什么时候被调度到 cpu 上执行的时机是不确定的
  2. 一个线程什么时候从 cpu 上下来, 给别人让位的时机也是不确定的

这是主流操作系统"抢占式执行"的体现, 但是给我们的多线程的安全问题埋下了伏笔

刚才我们只是通过打印的方式看到了两个执行流, 我们也可以使用一些第三方工具更直观地看到多个线程的情况

在 jdk 中, 有一个叫 jconsole 的工具 

选择本地进程中我们刚刚执行的 ThreadDemo2 代码, 然后直接连接即可, 

直接选择不安全的连接即可

线程是在正在不停的运行的, 当我们点击 Thread-0 线程的详细情况的一瞬间, 相当于"咔嚓"一个快照把这一瞬间的 Thread-0 线程的状态展示出来了 (再次点击时, 线程的详细情况可能会改变)

这里的"堆栈跟踪", 就是线程的调用栈, 描述了线程当前执行到哪个方法的第几行代码, 以及这个方法是如何一层一层调用过去的

除了 main 线程和 t 线程, 其余的线程都是 JVM 自带的线程, 完成一些垃圾回收, 以及监控统计各种指标 (如果我们的代码出现问题, 就可以从中提取一些参考和线索), 把统计指标通过网络的方式, 传输给其他程序,

 


3. 2 实现 Runnable 接口, 重写 run

只是实现接口时改变, 其余和上面的代码类似

package thread;// Runnable 可理解为 "可执行的", 通过这个接口, 就可以抽象出一段可以被其他实体执行的代码
class MyThread3 implements Runnable {@Overridepublic void run() {while (true) {System.out.println("hello runnable");//睡眠 1stry {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread(new MyThread3());t.start();while (true) {System.out.println("hello main");//睡眠 1stry {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

3.3 继承 Thread, 重写 run, 使用匿名内部类

内部类是在一个类里面定义的类, 最多使用的就是匿名内部类 (这个类没有名字, 不能重复使用, "用一次就扔掉")

package thread;public class ThreadDemo4 {public static void main(String[] args) {// 写 { 是因为要定义一个新的类, 继承自 Thread, {} 中定义子类的属性和方法, 此处最主要的目的是重写 run 方法// t 指向的实例不是单纯的 Thread, 而是新定义的匿名内部类 (Thread 的子类)Thread t = new Thread() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

3.4 实现 Runnable, 重写 run, 使用匿名内部类

package thread;public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {// Thread 构造的方法的参数, 填写了 Runnable 的匿名内部类的实例@Overridepublic void run() {while (true) {System.out.println("hello runnable");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

3.5  [常用/推荐] 使用 lambda 表达式

这是最简洁的写法

lambda 主流语言都有: c++, Python 中叫做 lambda, JS, GO 直接叫做匿名函数

因为方法不能脱离类单独存在, 所以导致上面几种方法为了设置回调函数 而套上了一层类

因此引入了 lambda 表达式 (就是一个匿名函数/方法), Java语法首创, 函数式接口属于 lambda 背后的实现, 相当于在没有破坏原有规则 (方法不能脱离类单独存在) 的基础上, 给了lambda 一个合理的解释

package thread;public class ThreadDemo6 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

4. 小结

上述的5种写法都是等价的, 可以互相转换的, 用 lambda 表达式是我们最常用, 最推荐, 最简洁的写法


最后,祝大家天天开心,更上一层楼!关注我🌹,我会持续更新学习分享...🖋️

相关文章:

JavaEE之多线程(创建线程的五种写法)详解

😽博主CSDN主页: 小源_😽 🖋️个人专栏: JavaEE 😀努力追逐大佬们的步伐~ 目录 1. 前言 2. 操作系统"内核" 3. 创建线程的五种写法 (我们重点要掌握最后一种写法!!) 3.1 继承 Thread, 重写 run 3. 2 实现 Runnabl…...

ChatGPT国内能用吗?中国用户怎么才能使用ChatGPT?

与ChatGPT类似的国内网站,他们都能提供和ChatGPT相似的能力,而且可以在国内直接使用。 点击直达方式 百科GPT官网:baikegpt.cn ChatGPT是基于GPT-3.5架构的语言模型的一个实例,由OpenAI开发。以下是ChatGPT的发展历史&#xff1…...

集群保持集群负载均衡和hash一致性

集群保持负载均衡和一致性哈希是在构建分布式系统时经常涉及的两个重要概念。 负载均衡: - 在集群中,负载均衡是指将传入的请求有效地分发到不同的服务器上,以确保每台服务器都能够处理适量的流量,避免某些服务器过载而造成性能问…...

吴恩达深度学习笔记:神经网络的编程基础2.9-2.14

目录 第一门课:神经网络和深度学习 (Neural Networks and Deep Learning)第二周:神经网络的编程基础 (Basics of Neural Network programming)2.9 逻辑回归中的梯度下降(Logistic Regression Gradient Descent) 第一门课&#xff…...

在C++项目中使用python脚本(四种)常见报错解决

上一期我们讲了如何在C中使用python脚本,这期讲讲过程中常会遇到的一些错误。 一、c代码未设置python路径 Py_SetPythonHome(L"D:\\anaconda3\\envs\\envpython3.7");这一句很重要,切记加上并且换成自己的路径 Py_SetPythonHome(L"D:\\a…...

微前端框架 qiankun 配置使用【基于 vue/react脚手架创建项目 】

qiankun官方文档:qiankun - qiankun 一、创建主应用: 这里以 vue 为主应用,vue版本:2.x // 全局安装vue脚手架 npm install -g vue/clivue create main-app 省略 vue 创建项目过程,若不会可以自行百度查阅教程 …...

nodejs切换淘宝源

1. 查看当前地址 npm config get registrynpm config get disturl2. 设置当前地址(设置为淘宝镜像) npm config set registry http://registry.npm.taobao.org/3. 设置当前地址(设置为默认地址) npm config set registry https…...

怎么避免电脑数据被拷贝?电脑如何禁用USB功能?

在无纸化办公的今天,很多重要数据都存放在电脑中。为了避免数据泄露,需要采用安全的方式保护电脑数据。那么,该如何避免电脑数据被拷贝呢?下面我们就来了解一下。 方法一:物理隔绝 物理隔绝是一种原始但有效的USB禁用…...

给电脑加硬件的办法 先找电脑支持的接口,再买相同接口的

需求:我硬盘太小,换或加一个大硬盘 结论:接口是NVMe PCIe 3.0 x4 1.找到硬盘型号 主硬盘 三星 MZALQ512HALU-000L2 (512 GB / 固态硬盘) 2.上官网查 或用bing查 非官方渠道信息,不确定。...

uniapp微信小程序_自定义交费逻辑编写

一、首先看最终效果 先说下整体逻辑,选中状态为淡紫色,点击哪个金额,充值页面上就显示多少金额 二、代码 <view class"addMoney"><view class"addMoneyTittle">充值金额</view><view class"selfaddmoney" :class"{…...

论文阅读——RingMo

RingMo: A Remote Sensing Foundation Model With Masked Image Modeling 与自然场景相比&#xff0c;RS图像存在以下困难。 1&#xff09;分辨率和方位范围大&#xff1a;受遥感传感器的影响&#xff0c;图像具有多种空间分辨率。此外&#xff0c;与自然图像的实例通常由于重…...

Hadoop,Hive 数据预处理CR

记录一次大材小用,我在将.csv电影数据集 电影json数据 导入MySQL时,出现了报错: 很明显,意味着.csv中的数据有非utf8编码的, 尝试使用file查看了下.csv文件的编码格式: 如果不确定原始编码,可以先用file命令尝试检测一下: file -i input.csv该命令会显示文件的MIME类型…...

小程序开发——获取设备信息 API(三)

ty.device.getShareDeviceInfo 获取共享设备信息 需引入DeviceKit&#xff0c;且在>2.2.0版本才可使用 请求参数 Object object 属性类型默认值必填说明deviceIdstring是deviceId 设备 idcompletefunction否接口调用结束的回调函数&#xff08;调用成功、失败都会执行&am…...

Vue2 + node.js项目

1、Vue2 vue2主要功能包括登入、退出、用户权限、表格的增删改查、文件下载。 Vue2项目地址https://gitee.com/www6/finance1.git 2、node.js编写后端接口 2.1、项目初始化 后端地址https://gitee.com/www6/finance-backend.git 创建项目 npm install -g koa-generator …...

如何使用IDE端通义灵码

如何使用IDE端通义灵码 第一步&#xff1a;安装IDE插件&#xff08; VS Code 和 JetBrains 二选一&#xff09; 如何下载安装VS Code &#xff1a;https://code.visualstudio.com 如何下载安装JetBrains&#xff1a;https://www.jetbrains.com/idea/download 第二步&#x…...

微服务分布式springcloud的体育场地预约系统演kdm1z

体育场馆设施预约系统是在实际应用和软件工程的开发原理之上&#xff0c;运用java语言以及Springcloud框架进行开发。首先要进行需求分析&#xff0c;分析出体育场馆设施预约系统的主要功能&#xff0c;然后设计了系统结构。整体设计包括系统的功能、系统总体结构、系统数据结构…...

IDEA开启Run Dashboard

1、Run Dashboard是什么&#xff0c;为什么要使用 Run Dashboard 是 IntelliJ IDEA 中的一个工具窗口&#xff0c;用于管理和监视项目中正在运行的应用程序和配置。它提供了一种集中管理运行和调试过程的方式&#xff0c;可以让开发人员更方便地查看和控制正在运行的应用程序。…...

小程序学习3 goods-card

pages/home/home home.wxml <goods-listwr-class"goods-list-container"goodsList"{{goodsList}}"bind:click"goodListClickHandle"bind:addcart"goodListAddCartHandle"/> <goods-list>是一个自定义组件&#xff0c;它具…...

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024)

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 图像处理 基于图像的渲染 计算机视觉 可视化分析 模式识别 3D打印 渲染和动画 渲染技术 电脑动画 基于草图的建模 机械…...

Linux系列

安装系列 1.MySQL安装 我们要通过rpm&#xff0c;进行MySQL数据库的安装&#xff0c;主要的步骤如下&#xff1a; rpm -qa 查询当前系统中安装的所有软件 rpm -qa | grep mysql 查询当前系统中安装的名称带mysql的软件 rpm -…...

SQL笔记 -- 黑马程序员

SQL目录 文章目录 SQL目录一、SQL分类1、DDL2、数据类型3、DML4、DQL1&#xff09;基本查询2&#xff09;条件查询3&#xff09;聚合函数查询4&#xff09;分组查询5&#xff09;排序查询6&#xff09;分页查询 5、DCL 一、SQL分类 分类说明DDL数据定义语言&#xff0c;用来定…...

C# MES通信从入门到精通(1)——串口传输文件

前言: 在上位机软件开发领域,有一些工厂的mes系统需要我们通过串口发送文件的方式把一些图片或者检测数据csv文件等发送给服务器,这种方式是一些比较旧的工厂采用的方式,但是这种方式也是存在的,本文就是讲解如何使用串口发送文件详情见下文。 1、串口发送文件思路 将需…...

论文阅读-federated unlearning via class-discriminative pruning

论文阅读-federated unlearning via class-discriminative pruning FUCP 通过类别区分性剪枝进行联邦遗忘 综述中描述&#xff1a;属于面向全局模型中的局部参数调整 利用卷积层的结构特定进行联邦忘却学习&#xff0c;wang等人提出了针对图像分类任务的联邦忘却学习算法FUCP&…...

研发效能DevOps: OpenEuler 部署 drone 持续集成平台

目录 一、实验 1.环境 2.OpenEuler 部署 drone 持续集成平台 二、问题 1.drone登录失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注LinuxopenEuler22.03 LTS SP2 192.168.204.145&#xff08;动态&#xff09; 192.168.204.141&…...

C#,图论与图算法,图着色问题(Graph Coloring)的威尔士-鲍威尔(Welch Powell Algorithm)算法与源代码

Welsh, D.J.A. and Powell, M.B. (1967) An Upper Bound for the Chromatic Number of a Graph and Its Application to Timetabling Problems. 《The Computer Journal》, 10, 85-86. 《The Computer Journal》 1 图着色算法概述 1967年&#xff0c;Welsh和Powell算法引入了…...

用python写一个脚本,实现加速3X并压缩mp4视频以降低文件大小。

为了实现您的需求&#xff0c;我们将使用Python的moviepy库来加速MP4视频3倍并使用ffmpeg选项来进行压缩&#xff0c;以降低文件大小。如果您还没有安装这些库&#xff0c;请先通过以下命令进行安装&#xff1a; pip install moviepy这是一个步骤概述&#xff1a; 读取视频文…...

Flink广播流 BroadcastStream

文章目录 前言BroadcastStream代码示例Broadcast 使用注意事项 前言 Flink中的广播流&#xff08;BroadcastStream&#xff09;是一种特殊的流处理方式&#xff0c;它允许将一个流&#xff08;通常是一个较小的流&#xff09;广播到所有的并行任务中&#xff0c;从而实现在不同…...

IP数据报格式

每一行都由32位比特&#xff0c;即4个字节组成&#xff0c;每个格子称为字段或者域。IP数据报由20字节的固定部分和最大40字节的可变部分组成。 总长度 总长度为16个比特&#xff0c;该字段的取值以字节为单位&#xff0c;用来表示IPv4数据报的长度(首部长度数据载荷长度)最大…...

GET https://registry.npm.taobao.org/xxxx error (CERT_HAS_EXPIRED)解决

PNPM用的阿里源&#xff0c;提示意思是证书过期了&#xff0c;参考网上的解决办法。执行 pnpm config set registry https://registry.npmmirror.com 再用pnpm config get registry查看&#xff0c;确实是 https://registry.npmmirror.com 但是仍旧报错&#xff0c;发现还…...

SSM Java Web项目由于spring-mvc.xml配置不对带来的一系列问题

1 介绍 一年多前&#xff0c;我就买了好多关于Java开发类的书籍&#xff0c;内容关于Java Web实操、Spring 学习指南、Maven实战、IntelliJ IDEA软件开发与应用等等。可是由于工作繁忙&#xff0c;这些书没系统地看完。这也是参加工作后的无奈吧&#xff01; 寒假期间的一周&…...