JavaEE初阶:多线程 - 编程
1.认识线程
我们在之前认识了什么是多进程,今天我们来了解线程。
一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行 着多份代码.
引入进程这个概念,主要是为了解决并发编程这样的问题。因为cpu进入了多核心的时代,要想进一步提高程序的执行速度,就需要充分的利用CPU的多核资源。
其实多进程编程,已经可以解决并发编程的问题了,它已经可以利用起来cpu多核资源了,但是问题是:
进程太重了(消耗资源多、速度慢)创建一个进程,开销比较大。
销毁一个进程,开销也比较大。
调度一个进程,开销还比较大。
说进程重,主要就是重在资源分配/回收上。
线程应运而生,线程也叫做"轻量级进程",
解决并发编程问题的前提下,让创建,销毁,调度的速度更快一些
线程为啥更"轻",把申请资源/释放资源的操作给省下了。
1.1 进程和线程的区别
进程是包含线程的。每个进程至少有一个线程存在,即主线程。
进程和进程之间不共享内存空间。同一个进程的线程之间共享同一个内存空间。
进程是系统分配资源的最小单位,线程是系统调度的最小单位。
光靠文字可能有点抽象,我们举个例子:
多进程:
多线程:
在多进程中,启用了两套院子,那么启用的成本是比较大的,耗费的时间也是比较多的,但是在第二套中,院子和运输材料的通道都是公用的,那么就节省了成本。
在启动一个新的生产线时,就不需要重新启动一个院子,而是在原来的院子里启用,节省了许多的成本。
线程和进程的关系,是进程包含线程,
一个进程可以包含一个线程,也可以包含多个线程,但是不能没有。
对比下来,主要的优势在于:
只有第一个线程启动的时候,开销是比较大的,但是后续线程就省事了.,不论是启动还是关闭,耗费的资源都比启动/关闭一个进程要小。同一个进程里的多个线程之间,共用了进程的同一份资源(主要指的是内存和文件描述符表)。这样这一部分资源就不需要重新启动或关闭。
操作系统,实际调度的时候,是以线程为单位进行调度的。
之前介绍的,,PCB里的状态,上下文,优先级,记账信息,都是每个线程有自己的。各自记录各自的但是同一个进程里的PCB之间, ,pid是一样的,内存指针和文件描述符表也是一样的。
那么既然线程这么好,可不可以无限制的在一个进程中增加线程呢?
并不可以,线程如果太多,核心数量有限,那么不少的开销就会浪费在线程调度上了,但是在多进程中就不会出现这样的状况。
线程模型,天然就是资源共享的.多线程争抢同一个资源(同一个变量)非常容易触发的.
进程模型,天然是资源隔离的.不容易触发.进行进程间通信的时候,多个进程访问同一个资源,可能会出问题.
1.2 多线程编程
本身关于线程的操作,操作系统提供的API,我们只需要学习Java提供的API就好了。
Java操作多线程,最核心的类 :Thread
先在src下创建一个包,接着再创建一个类
创建好主函数后,我们新建一个Thread的对象
Thread t = new Thread();
但是我们还需要一个类,新建一个Mythread类,并且重写run方法
class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}
然后在main中,开始启动一个特殊的方法:
t.start;
完整的代码:
class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("hello main");}
}
这样一个代码,就新启动了一个线程,使得打印hello world和打印hello main是以完全不同的方式来完成的。
start这里的工作,就是创建了一个新的线程,新的线程负责执行重写过后的t.run。
具体的执行方法,就是start这个方法会调用操作系统的API,通过操作系统内核创建新线程的PCB,并且把要执行的指令交给PCB,当PCB被调度到CPU上执行的时候,也就执行到了线程run方法中的代码了。
通过具体的结果,,两个线程是同时进行的,并且可以看做是一次运行时无序,可能先打印world,也可能先打印main。
但是运行的时候不一定谁先谁后,
操作系统调度线程的时候,"抢占式执行",具体哪个线程先上,哪个线程后上,不确定,取决于操作系统调度器具体实现策略.
虽然有优先级,但是在应用程序层面上无法修改.
从应用程序(代码)的角度,看到的效果,就好像是线程之间的调度顺序是"随机"的一样.
内核里本身并非是随机.但是干预因素太多,并且应用程序这一层也无法感知到细节,就只能认为是随机的了。
为啥会有线程安全问题?罪魁祸首,万恶之源,就是这里的抢占式执行,随机调度。
start和run的区别
start是真正创建了一个线程(从系统这里创建的),线程是独立的执行流。
run 只是描述了线程要干的活是啥,如果直接再main中调用run,此时没有创建新线程,全是main线程一个人干活。相当于还是单线程。
可以使用jdk自带的工具jconsole查看当前的java进程中的所有线程.
这里面就可以看到进程。同时进程中还有很多个线程。除了我们使用的,其他的都是JVM自带的
1.3 多线程的五种创建方法
1.继承Thread,重写run方法
class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello world");}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("hello main");}
}
也就是上面详细介绍的方法。
2.实现 Runnable 接口
class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("hello thread");}
}
public class ThreadDemo2 {public static void main(String[] args) {Runnable runnable = new MyRunnable();Thread t = new Thread(runnable);t.start();}
}
Runnable 作用,是描述一个“要执行的任务”,然后把这个任务交给Thread来执行。
好处就是这样写可以解耦合,让线程和线程之间干的活要分开。
3.使用匿名内部类,继承 Thread
public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {System.out.println("hello");}};t.start();}
}
这里面创建了一个Thread的子类,并且创建了子类的实例,让 t 引用指向该实例。
4.使用匿名内部类,实现 Runable
public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("hello demo4");}});t.start();}
}
这个写法和2本质相同,只不过是把Runnable任务交给匿名内部类的语法。
此处是创建了一个类,实现Runnable,同时创建了类的实例,并且传给Thread的构造方法。
5.使用 Lambda 表达式(推荐)
public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello demo5");});t.start();}
}
使用lambda表达式来描述,直接把lambda传给Thread构造方法。
相关文章:

JavaEE初阶:多线程 - 编程
1.认识线程 我们在之前认识了什么是多进程,今天我们来了解线程。 一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行 着多份代码. 引入进程这个概念,主要是为了解决并发编程这样的…...

一种多策略下RabbitMQ的延时队列实现
1.为什么会用到延时队列? 场景: 最近在开发一款系统中遇到这样一个场景,A系统开通套餐需要把套餐信息以邮件的形式发送给相关工作人员,经过人工审核通过后,在B系统里面开通,A系统会调B系统套餐列表接口查询套餐是否开通成功,开通成功则从A系统去完成订单,假如超过设定时间未开…...

解密 AI 客服;在不同硬件设备上运行大型语言模型的可能性
🦉 AI新闻 🚀 微软必应首席执行官称必应聊天优于OpenAI的GPT-4,但成本更高 摘要:微软必应的首席执行官米哈伊尔・帕拉欣表示,必应聊天表现优于OpenAI的GPT-4,但使用了更高成本的检索增强推理技术。必应聊…...

问题:【IntelliJ IDEA】解决idea自动声明变量加finall修饰符问题
问题:【IntelliJ IDEA】解决idea自动声明变量加finall修饰符问题 场景复现 1 new String() 2 快捷方式生成变量 final修饰的 final String s new String();步骤一:确保settings配置信息 settings-----》Editor------》Code Style--------》java下的这两个选项不…...

SpringBoot基于Zookeeper实现分布式锁
文章目录 问题背景前言实现搭建Zookeeper容器引入依赖ZK客户端的配置类ZK客户端的工厂类注入bean构建测试类 问题背景 研究分布式锁,基于ZK实现,需要整合到SpringBoot使用 前言 参考自SpringBoot集成Curator实现Zookeeper基本操作,Zookeeper入…...

AT89C51单片机实现单片机串口互动(中断方式,单片机--单片机,应答)
说一下功能:客户机发送0x01到服务机 2服务单片机应答0xf2到客户机 3客户机接收到0xf2,发送信息153432这6个数字到服务机 4client发送完信息后发送0xaa结束通信 5server接收到0xaa后回复0xaa结束通信,从此老死不相往来 看代码: //发送端…...

九耶丨阁瑞钛伦特-请说说你在工作中的PRD文档是如何撰写的?
1、背景说明(解释清楚为什么要做这样一件事,以及做这件事的价值,先把观点拉齐,才方便接下来的工作开展) 简要介绍与项目相关的背景信息、项目要满足的用户需求、开展项目的主要原因、项目期望上线时间、项目涉及的具体…...

Android免打包多渠道统计如何实现
摘要: 实际上只要完成1-2步即可实现多渠道打包,这也意味着,只要每次更新App时给出一个原始包,运营人员就能在后台自己进行操作管理,简单快捷到全程无需开发人员参与。 我们都知道,Android 市场被分割成几十…...

Apipost CICD怎么配置?
配置CI/CD Apipost自动化测试新增CI/CD,配置运行环境、循环次数、间隔停顿后点击保存会生成命令,在安装Apipost的服务器中输入命令即可运行测试脚本。 自动化测试 创建自动化测试脚本在创建好的测试用例中选择「CICD」,点击新建,…...
utf-8和utf-8 mb4区别
UTF-8(Unicode Transformation Format-8)和UTF-8MB4(UTF-8 Multibyte 4-byte)是字符编码方案,用于表示 Unicode 字符集中的字符。它们之间的主要区别在于编码范围。 UTF-8:UTF-8 是一种变长编码方式&#x…...

考研 408 | 【计算机网络】 应用层
导图 网络应用模型 客户/服务器(c/s)模型 P2P模型 DNS 域名 域名服务器 域名解析过程 文件传输协议FTP FTP服务器和用户端 FTP工作原理 电子邮件 电子邮件的信息格式 组成结构 邮件服务器的功能: 1.发送&接收邮件 2.给发件人报告邮…...
设计模式-单例
概述 在类加载后,整个系统只有一个实例类 饿汉式 public class Mg1 {private static final Mg1 INSTANCE new Mg1();private Mg1(){}public static Mg1 getInstance(){return INSTANCE;}public static void main(String[] args) {System.out.println(Mg1.getIns…...
mysql截取最后一个字符之前的数据
1、mysql截取最后一个字符之前的数据 select --截取斜杠之前的数据REVERSE(SUBSTR(REVERSE(SPNH-dfg-2012) ; --截取斜杠后的数据 INSTR(REVERSE(SPNH-fg-2012),-)1))2、mysql获取最后一个字符后的数据 select SUBSTRING_INDEX(SPNH-dfg-2012,-,-1) 3、mysql更新某个字段…...
Flutter 中,ListView 中需要放置 ListView 需要怎么处理才高效?
问题及场景 ListView 是 Flutter 开发者第一个学习到的 Widget,因为它可以滑动。一切都会运行得很好,直到 ListView 中的 Item 本身也是一个 ListView。你可能会看到 Flutter 建议你将内部的 ListView 的ShrinkWrap 属性设置为 True。虽然错误消除了&am…...

Appium Desktop安装
【提示:官方已不再维护,建议命令行方式安装,但可以学习了解一下】 Appium Desktop是一款适用于Mac、Windows和Linux的应用程序,它以漂亮灵活的UI为您提供Appium自动化服务器的强大功能。它基本上是Appium Server的图形界面。您可…...

Open3D 最小二乘拟合平面(SVD分解法)
目录 一、算法原理二、代码实现三、结果展示1、点云2、拟合结果四、优秀博客本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 本文实现矩阵奇异值分解方法的最小二乘拟合平面。原理如下: 对于得到的 n n...

Pytorch源码搜索与分析
PyTorch的的代码主要由C10、ATen、torch三大部分组成的。其中: C10 C10,来自于Caffe Tensor Library的缩写。这里存放的都是最基础的Tensor库的代码,可以运行在服务端和移动端。PyTorch目前正在将代码从ATen/core目录下迁移到C10中。C10的代…...

运维监控学习笔记9
2、画出拓扑图的小案例: 3、在连接的线上显示网络流量,使用了一个简单的公式: {nginx-server:net.if.out[ens33].last(0)} 4、在screens中显示nginx的状态页面: 5、zabbix报警: 发送邮件的选项。Email可以使用…...

gulimall-缓存-缓存使用
文章目录 前言一、本地缓存与分布式缓存1.1 使用缓存1.2 本地缓存1.3 本地模式在分布式下的问题1.4 分布式缓存 二、整合redis测试2.1 引入依赖2.2 配置信息2.3 测试 三、改造三级分类业务3.1 代码改造 四、高并发下缓存失效问题4.1 缓存穿透4.2 缓存雪崩4.3 缓存击穿 五、分布…...

概述、搭建Redis服务器、部署LNP+Redis、创建Redis集群、连接集群、集群工作原理
Top NSD DBA DAY09 案例1:搭建redis服务器案例2:常用命令限案例3:部署LNPRedis案例4:创建redis集群 1 案例1:搭建redis服务器 1.1 具体要求如下 在主机redis64运行redis服务修改服务运行参数 ip 地址192.168.88.6…...

unidbg patch 初探 微博deviceId 案例
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 看了b站迷人瑞信那个由于是…...

循序渐进 Android Binder(一):IPC 基本概念和 AIDL 跨进程通信的简单实例
Binder 给人的第一印象是”捆绑者“,即将两个需要建立关系的事物用某些工具束缚在一起。在 Android 中,Binder 是一种高效的跨进程通信(IPC)机制,它将可以将运行在不同进程中的组件进行绑定,以实现彼此通信…...
机器视觉2D定位引导一般步骤
机器视觉的2D定位引导是工业自动化中的核心应用,主要用于精确确定目标物体的位置(X, Y坐标)和角度(旋转角度θ),并引导机器人或运动机构进行抓取、装配、对位、检测等操作。其一般步骤可概括如下: 一、系统规划与硬件选型 明确需求: 定位精度要求(多少毫米/像素,多少…...

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)
给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性: 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意:直线的一般方程是 a*x b*y c 0,因此输入中只给出常数 a、b、…...
解决:输入SSH后,仍无法通过网址登录以及紧接着的新问题Permission denied(publickey,password).
现象: 管理员: Windows PowerShell输入SSH后,仍无法通过网址登录 例如输入你的ssh命令:ssh -CNg -L xxxx:127.0.0.1:xxxx rootaaaaaaaaa.com -p yyyyy 得到终端提示:ssh无法识别为 cmdlet、函数、脚本文件或可运行程序的名称。 解…...

[Windows]在Win上安装bash和zsh - 一个脚本搞定
目录 前言安装步骤配置要求下载安装脚本启动程序 前言 Windows是一个很流行的系统, 但是在Windows上安装bash和zsh一直是一个让人头疼的问题. 本蛙特意打包了一个程序, 用于一站式解决这一类的问题. 安装步骤 配置要求 系统: Windows软件: Powershell 5.1或以上 下载安装…...

sigmastar实现SD卡升级
参考文章:http://wx.comake.online/doc/DD22dk2f3zx-SSD21X-SSD22X/customer/development/software/Px/zh/sys/P3/usb%20&%20sd%20update.html#21-sd 1、构建SD卡升级包 在project下make image完成后使用make_sd_upgrade_sigmastar.sh脚本打包SD卡升级包。 ./make_sd_up…...

android binder(1)基本原理
一、IPC 进程间通信(IPC,Inter-Process Communication)机制,用于解决不同进程间的数据交互问题。 不同进程之间用户地址空间的变量和函数是不能相互访问的,但是不同进程的内核地址空间是相同和共享的,我们可…...
Java异常处理的全面指南
Java异常处理的全面指南 一、Java异常的基础概念1.1 什么是异常1.2 异常类的层次结构 二、Java异常的处理方式2.1 try-catch块2.2 throws关键字2.3 throw关键字 三、自定义异常3.1 自定义受检异常3.2 自定义非受检异常 四、Java异常处理的最佳实践4.1 捕获合适粒度的异常4.2 避…...
判断使用什么技术来爬取数据详细讲解
判断目标网站使用哪种数据加载形式是爬虫开发的第一步,也是最关键的一步。以下是系统化的诊断方法和步骤: 核心诊断流程 (使用浏览器开发者工具 - Chrome/Firefox为例) 初始观察 (肉眼判断) 页面加载后数据是否立刻可见? 是 → 可能是静态HTM…...