5.多线程学习
作者:爱塔居
专栏:JavaEE
作者简介:大三学生,喜欢总结与分享~
文章目录
目录
文章目录
章节回顾
一、wait 和notify
二、设计模式
2.1 单例模式
章节回顾
线程安全
1.一个线程不安全的案例(两个线程各自自增5w次,结果不是10w)
2.线程不安全的原因
(1)抢占式执行,随机调度。线程中的代码执行到任意一行,都随意可能被切换出去。
(2)多个线程同时修改同一个变量。
(3)修改操作不是原子的。
(4)内存可见性(volatile)编译器可能会对我们的代码进行优化。
一个线程频繁读,一个线程修改
(5)指令重排序。
除了这些原因,还有其他原因。
3.解决方案 加锁
在线程1加锁的过程中,线程2无法把自己的指令插入到线程1的修改过程中。
synchronized指定一个“锁对象”
4.volatile
关于volatile和内存可见性补充
内存可见性:
t1频繁读取主内存,效率比较低,就被优化成直接读自己的工作内存。
t2修改了主内存的结果,由于t1没有读主内存,导致修改不能被识别到。
工作内存=>CPU寄存器
主内存=>内存
工作内存和主内存都是由英文work memory和main memory翻译来的。所以,工作内存不一定非要是内存,可以是记忆,存储区,不一定是特指“内存条”。
这一套说法,也称为JMM(java memory model)
java是跨平台的。
1.兼容多种操作系统
2.兼容多种硬件设备
不同的硬件,其实差别很大。cpu和cpu之间,差别就会比较大。
像以前的cpu,上面只有寄存器。现在的cpu上面还有缓存。
而且有的cpu缓存还有好几个,L1,L2,L3,(现在常见的cpu都是3级缓存)
工作内存准确来说,代表cpu寄存器+缓存(CPU内部存储数据的空间)
cpu读储存器速度比读内存快3-4个数量级。
缓存读取速度介于寄存器和内存之间。
L1最快,空间最小(仍然比寄存器慢)
L3最快,空间最大(仍然比内存快很多)
实际上cpu尝试读一个内存数据:
1.先看寄存器里有没有
2.没有,看L1有没有
3.没有,看L2有没有
4.没有,看L3有没有
5.没有,看内存有没有
具体缓存的大小,对于程序效率的影响,也看实际的应用场景。
一、wait 和notify
线程的调度是无序的,随机的。但是,也是有一定的需求场景的,希望线程有序执行。
join是一种控制顺序的方式,但是功效有限。
wait就是让某个线程先暂停下来,等一等。
wait主要做三件事:
1.解锁
2.阻塞等待
3.当收到通知的时候,就唤醒,同时尝试重新获取锁。
notify就是把该线程唤醒,能够继续执行。
wait和notify是Object的方法
只要你是个类对象(不是内置类型/基本数据类型),都是可以使用wait和notify。
public class test {static int i;public static void main(String argv[]) throws InterruptedException{Object locker=new Object();Thread t1=new Thread(()->{while (true){try {System.out.println("wait 开始");synchronized (locker){locker.wait();}System.out.println("wait 结束");}catch (InterruptedException e){e.printStackTrace();}}});t1.start();Thread.sleep(1000);Thread t2=new Thread(()->{synchronized (locker){System.out.println("notify 开始");locker.notify();System.out.println("notify 结束");}});t2.start();}
}
使用外套,阻塞等待会让线程进入WAITING状态。wait也提供了一个带参数的版本,参数指定的是最大等待时间。不带参数的wait是死等,带参数的wait就会等最大时间之后,还没有人通知,就自己唤醒自己。
wait会导致阻塞,竞争锁也会导致阻塞,两种不同的进入阻塞的方式。wait的初心就是为了实现阻塞的效果。
join只能是让t2的线程先执行完,再继续执行t1,一定是串行的
wait、notify,可以让t2执行完一部分,再让t1执行一部分,再让t2去执行,再……
唤醒操作,还有一个notifyAll。可以有多个线程,等待同一个对象。
比如在t1,t2,t3中都调用object.wait。此时在main中调用了object.notify 会随机唤醒上述的一个线程。(另外两个仍然会是waiting状态)
如果是调用了object.notifyAll,此时就会把上述三个线程都唤醒。伺候这三个线程就会重新竞争锁,然后依次执行。
总结:
1.wait需要搭配synchronized使用,sleep不需要。
2.wait是Object的方法,sleep是Thread的静态方法。
wait和sleep都是可以提前唤醒的。
他们最大的区别在于初心不同。
wait解决的是线程之间的顺序控制
sleep单纯是让当前线程休眠一会。
二、设计模式
设计模式,就是软件开发中的棋谱。大佬们针对一些常见场景,总结出来的代码的编写套路。设计模式有很多种。
在校招阶段,主要考察两个设计模式。
1.单例模式
2.工厂模式
设计模式需要大家有一定的开发经验的积累,才好理解。
2.1 单例模式
单例指的是单个实例(instance)对象。类的实例,就是对象。Java中的单例模式,借助java语法,保证某个类,只能够创建出一个实例,而不能new多次。
有些场景,本身就是要求某个概念是单例的。
//把这个类设定为单例
class Singleton{//唯一的实例的实体
private static Singleton instance=new Singleton();
//被static修饰,该属性是类的属性。JVM中,每个类的类对象只有唯一一份,类对象里的这个成员自然也是唯一一份了。
//获取到实例的方法public static Singleton getInstance(){return instance;}//禁止外部new实例private Singleton(){};
}
public class test {public static void main(String[] args) {Singleton s1=Singleton.getInstance();Singleton s2=Singleton.getInstance();}}
java中实现单例模式是有多种写法的。
主要说两种:
1.饿汉模式(急迫)
2.懒汉模式(从容)
A吃完饭立马洗碗(饿汉行为)
B吃完饭,不洗碗,等下一顿要用碗的时候,再洗碗。(懒汉行为)
通常认为,懒汉模式更好,效率更高。(非必要,不洗碗)
举一个计算机的例子:
打开一个硬盘上的文件,读取文件内容,并显示出来。
饿汉:把文件所有内容都读到内存中,并显示出来
懒汉:只把文件读一小部分,把当前的屏幕填充上,如果用户翻页,再读其他文件内容。
当文件特别大的时候,就可以看出懒汉模式的优势了。
饿汉模式:
//把这个类设定为单例,饿汉
class Singleton{//唯一的实例的实体
private static Singleton instance=new Singleton();
//被static修饰,该属性是类的属性。JVM中,每个类的类对象只有唯一一份,类对象里的这个成员自然也是唯一一份了。
//获取到实例的方法public static Singleton getInstance(){return instance;}//禁止外部new实例private Singleton(){};
}
public class test {public static void main(String[] args) {Singleton s1=Singleton.getInstance();Singleton s2=Singleton.getInstance();}}
懒汉模式:
//把这个类设定为单例模式中的懒汉模式。
class SingletonLazy{
private static SingletonLazy instance=null;public static SingletonLazy getInstance(){if(instance==null){instance=new SingletonLazy();}return instance;}private SingletonLazy(){};
}
public class test {public static void main(String[] args) {SingletonLazy s1=SingletonLazy.getInstance();SingletonLazy s2=SingletonLazy.getInstance();System.out.println(s1==s2);}}
饿汉模式一开始就把实例创建好了,而懒汉模式是非必要不创建实例。
上述两个代码,是否是线程安全的?多个线程下调用getInstance,是否会出现问题?
饿汉模式,认为是线程安全的,只是读数据。
而在多线程下,懒汉模式可能无法保证创建对象的唯一性。
比如以下情况:
如何解决上诉线程安全问题?
进行加锁,保证判定和new操作是原子性的。
//把这个类设定为单例模式中的懒汉模式。
class SingletonLazy{
private static SingletonLazy instance=null;synchronized public static SingletonLazy getInstance(){if(instance==null){instance=new SingletonLazy();}return instance;}private SingletonLazy(){};
}
public class test {public static void main(String[] args) {SingletonLazy s1=SingletonLazy.getInstance();SingletonLazy s2=SingletonLazy.getInstance();System.out.println(s1==s2);}}
相关文章:

5.多线程学习
作者:爱塔居 专栏:JavaEE 作者简介:大三学生,喜欢总结与分享~ 文章目录 目录 文章目录 章节回顾 一、wait 和notify 二、设计模式 2.1 单例模式 章节回顾 线程安全 1.一个线程不安全的案例(两个线程各自自增5w次&…...

数据结构中的堆
一、树的重要知识点 节点的度:一个节点含有的子树的个数称为该节点的度(有几个孩子)叶节点或终端节点:度为0的节点称为叶节点;如上图:B、C、H、I...等节点为叶节点(0个孩子)非终端节点或分支节点…...

Linux内核设备信息集合
本文结合设备信息集合的详细讲解来认识一下设备和驱动是如何绑定的。所谓设备信息集合,就是根据不同的外设寻找各自的外设信息,我们知道一个完整的开发板有 CPU 和各种控制器(如 I2C 控制器、SPI 控制器、DMA 控制器等)࿰…...

若依框架---权限管理设计
前言 若依权限管理包含两个部分:菜单权限 和 数据权限。菜单权限控制着我们可以执行哪些操作。数据权限控制着我们可以看到哪些数据。 菜单是一个概括性名称,可以细分为目录、菜单和按钮,以若依自身为例: 目录,就是页…...
Java设计模式(二)——工厂模式
当用户需要一个类的子类实例,且不希望与该类的子类形成耦合或者不知道该类有哪些子类可用时,可采用工厂模式;当用户需要系统提供多个对象,且希望和创建对象的类解耦时,可采用抽象工厂模式。 工厂模式一般分为简单工厂、…...

【Maven】
MavenMaven简介仓库坐标Maven项目构建依赖管理生命周期及插件插件模块拆分与开发聚合继承属性版本管理资源配置多环境开发配置跳过测试私服Maven简介 Maven的本质时一个项目管理工具,将项目开发和管理过程抽象成一个项目对象模型(POM) POM(Project Object Model)&a…...

[JAVA]继承
目录 1.继承的概念 2.继承的语法 3.父类成员访问 3.1子类中访问父类成员变量 3.2子类中访问父类成员方法 4.super关键字 5.子类构造方法 6.继承方式 7.final关键字和类的关系 面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复…...

Vue3 pinia持久化存储(组合式Api案例演示)
pinia-plugin-persist( pinia持久化插件) 本文采用的是 组合式Api的方式来做Pinia的持久化存储演示 如果对pinia的持久化还是不是很了解的👨🎓|👩🎓,可以看一下笔者的上一篇文章…...
8个你一看就觉得很棒的Vue开发技巧
1.路由参数解耦 通常在组件中使用路由参数,大多数人会做以下事情。 export default {methods: {getParamsId() {return this.$route.params.id}} }在组件中使用 $route 会导致与其相应路由的高度耦合,通过将其限制为某些 URL 来限制组件的灵活性。 正…...

vue3+ts 开发效率提升
1、vite pnpm项目初始化 pnpm: 比npm或yarn快10倍 pnpm与其他包管理器(如npm和Yarn)的不同之处在于它使用一种称为“硬链接”的独特安装方法。当你使用PNPM安装一个包时,它并不会将包的文件复制到每个项目的node_modules目录中&a…...

【数据结构与算法】队列和栈的相互实现以及循环队列
目录🌔一.用队列实现栈🌙1.题目描述🌙2.思路分析🌙3.代码实现⛈二.用栈实现队列☔1.题目描述☔2.思路分析☔3.代码实现🌈三.实现循环队列🌔一.用队列实现栈 🌙1.题目描述 我们先看一下题目链接…...
mysql连接不上问题解决
公司新搭内网测试环境,mysql远程登录问题解决 远程登录: 1 修改host, mysql> select user,host,plugin from user; ---------------------------------------------------- | user | host | plugin | ------------------------…...

利用nginx实现动静分离的负载均衡集群实战
前言 大家好,我是沐风晓月,今天我们利用nginx来作为负载,实现两台apache服务器的动静分离集群实战; 本文收录于沐风晓月的专栏《linux基本功-系统服务实战》,更多内容可以关注我的博客: https://blog.csd…...

与chatGPT神聊,引领你深入浅出系统调用
在操作系统的教学中,系统调用的作用不言而喻,但是,对系统调用常常是雾里看花,似乎明白,又难以真正的触及,即使在代码中调用了系统调用,比如调用fork()创建进程࿰…...

自学大数据第十天~Hbase
随着数据量的增多,数据的类型也不像原来那样都是结构化数据,还有非结构化数据; Hbase时google 的bigtable的开源实现, BigtableHbase文件存储系统GFSHDFS海量数据处理MRMR协同管理服务chubbyzookeeper虽然有了HDFS和MR,但是对于数据的实时处理是比较困难的,没有办法应对数据的…...
vue更高效的工具-vite
目录 1.webpack 2.vite是什么 3.使用vite创建项目 4.最后总结 🐼webpack 简单来说,Webpack是一个打包工具。 站在2018年的角度,成为一个优秀的前端工程师,除了要会写页面样式和动态效果之外,还需要会用主流的单页…...

HFish蜜罐的介绍和简单测试(一)
目录 0、什么是蜜罐 0.1、蜜罐的定义 0.2、蜜罐的优势 0.3、蜜罐与情报 1、HFish介绍 1.1、设计理念 1.2、HFish架构 1.3、HFish特点 1.4、常见蜜罐场景 2、快速部署 2.1、环境要求 2.2、联网环境,一键安装 2.3、安装效果 3、错误排查 3.1、管理端问题…...
2023面试题汇总二
一、CSS面试题 1. 清除浮动的方式有哪些? 为什么要清除浮动?因为浮动的盒子脱离标准流,如果父盒子没有设置高度的话,下面的盒子就会撑上来。 额外标签法(在最后一个浮动标签后,新加一个标签,给其设置cle…...
C# 支付宝接口在线收款退款
收款 在C#中使用支付宝在线支付功能,需要使用支付宝开放平台提供的SDK(软件开发工具包),通过SDK中提供的API(应用程序接口)实现在线支付功能。 以下是使用C#实现支付宝在线支付的大致步骤: 获…...

python例程:《企业编码生成系统》程序
目录《企业编码生成系统》程序使用说明主要代码演示源码及说明文档下载路径《企业编码生成系统》程序使用说明 在PyCharm中运行《企业编码生成系统》即可进入如图1所示的系统主界面。在该界面中可以选择要使用功能对应的菜单进行不同的操作。在选择功能菜单时,只需…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...