当前位置:网站首页>多线程基础部分Part2
多线程基础部分Part2
2022-06-27 05:40:00 【小白的含金量】
目录
2.修饰静态方法,锁的是当前class对象(全局唯一,相当于把类锁上了)
线程安全
Java内存模型(JMM)
JMM是描述线程的工作内存(概念,并不真实存在,就是一系列CPU的寄存器或高速缓存)和主内存(真实存在的RAM)之间的关系。
工作内存
每个线程都有自己的工作内存,当访问共享变量时(类中的成员变量,常量,静态变量),会先将主内存中的共享变量值拷贝一份放到线程自己的工作内存中,之后对此共享变量的读取操作都是在当前工作内存中进行的。
为什么线程会不安全
当两个进程同时访问同一共享变量时,会出现各种各样的问题,因为每个线程实际上都是将共享变量加载到自己的工作内存中进行各种操作的,这就导致了,各个线程之间的工作内存可能会出差错,有可能数据在主内存更新后,某一个线程的工作内存仍保存着之前还未更新的数据,并且用这个数据进行操作再写回主内存。也有可能,其他线程此刻还没有加载共享变量,此时从主内存读共享变量值有可能还没读到新修改的值。(脏读)
保证线程安全的三大特性
可见性
一个线程对于共享变量的修改可以让其他线程立刻感知并可见(synchronized-上锁,volatile关键字,final关键字也可以保证可见性)
原子性
一个操作在进行中,无法被中断和打扰称为原子性,例如:
int i = 10; 这行代码就是原子性的,因为它顺时发生,没有被打断的机会。
i++ ; 就不是原子性的,因为在它加的时候可能会被别的线程读取。
防止指令重排
简单理解来说就是,在一个方法中,不影响最终结果的代码顺序是随意的,这种现象称为指令重排,但是如果在多线程中则会出现各种问题,例如此图:

synchronized关键字:线程上"锁",保证安全
synchronized-监视器锁 monitor lock
什么是锁?
举一个不是很恰当的例子,我们可把每一个线程比作一个人,把上锁的代码块比作厕所,若这些个线程需要上同一个厕所,那么可以假设先进去一个线程,进去之后线程就会把这个厕所的门锁上,这期间别的线程想进也是进不去的,这个就是线程间的互斥现象,只有等这个线程出来才能进去。
如果线程间不需要抢同一个厕所,那么就可以说是不存在互斥问题,因为一个线程进一个厕所上不同的锁。

互斥现象
当某个线程需要获取对象的锁时,其他线程若也要获取同一个线程的锁,就会处于阻塞状态。
一定要注意,互斥现象只发生在线程对于同一对象的操作,不同的对象间是不存在互斥现象的。
线程获取对象锁的过程

每个线程进入synchronized代码块,都会尝试执行加锁操作。
退出代码块的时候,就是释放这个锁。

上锁操作如何保证线程安全
synchronized代码块刷新内存
线程执行synchronized代码块的流程
a.获取对象锁
b.从主内存拷贝变量值到工作内存
c.执行代码
d.将更改后的值写回主内存
e.释放对象锁
因为在同一时间内,只有一个线程能进入上锁代码,保证互斥,此时这个代码块是一个单线程操作,不涉及线程不安全的问题。所以上锁操作也是天然的原子性和可见性的体现。

synchronized的不同使用方式
1.修饰类中的成员方法,锁的对象就是当前成员类对象

2.修饰静态方法,锁的是当前class对象(全局唯一,相当于把类锁上了)

此时只要调用此类对象,同一时间只有一个线程可以执行increase2方法

3.修饰代码块,明确所的是哪个对象
锁的粒度更细,用的最多,只要在需要锁上的若干代码加上synchronzied关键字即可
我们可以通过this锁定每一个对象

也可以通过.class直接锁定整个类

甚至可以自己来传递参数,自定义线程间的互斥关系

Java标准库中的线程安全类
我们之前学习的集合类在多线程中都是不安全的

所以为了保证线程安全,我们可以使用如下几种类:

这些类全部来自java.util.concurrent类(Java并发工具包)

这些类可以保证线程安全,例如:
ConcurrentHashMap类:把方法全部上了锁

volatile关键字
1.可以保证共享变量可见性
volatile关键字可以强制线程读写主内存的变量值
相当于普通的共享变量,此关键字可以保证共享变量的可见性

a.当线程读取的是此关键字修饰的内容时,线程直接从主内存读取该值到工作内存,无论当前工作内存是否由该值
b.当线程写此关键字变量时,将当前修改后的变量值立刻从工作内存中刷新到主内存,并且在此过程中其他线程会等待(不是阻塞),直到写回主内存的操作完成,保证读的一定是刷新后的值
对于同一个volatile变量,他的写操作一定是发生在读操作前的,保证读到的是主内存刷新后的数据。
volatile只能保证可见性,不能保证原子性,所以如果线程不是原子性操作依旧不安全。
2.使用volatile修饰的变量相当于一个内存屏障
volatile修饰的代码可以防止指令重排,也就是它一定是在前面的代码执行结束后,后面的代码执行前执行,无论CPU觉得哪种方式更优,volatile修饰的代码执行位置是固定的。

边栏推荐
- Spark 之 built-in functions
- 快速排序(非遞歸)和歸並排序
- 重映像(STM32)
- When STM32 turns off PWM output, it is a method to fix IO output at high or low level.
- 躲避小行星游戏
- 流媒体协议初探(MPEG2-TS、RTSP、RTP、RTCP、SDP、RTMP、HLS、HDS、HSS、MPEG-DASH)
- Opencv实现对象跟踪
- Implementation of easyexcel's function of merging cells with the same content and dynamic title
- C# netcore中 配置帮助类IConfiguration
- Mechanical transcoding journal [17] template, STL introduction
猜你喜欢
![Mechanical transcoding journal [17] template, STL introduction](/img/78/926db660139fda3d31cceccad7096c.png)
Mechanical transcoding journal [17] template, STL introduction

认知篇----2022高考志愿该如何填报

LeetCode-515. 在每个树行中找最大值

NLP-D62-nlp比赛D31&刷题D15

导航【机器学习】

Qt使用Valgrind分析内存泄漏

Gao Xiang slam14 lecture - note 1

Tsinghua University open source software mirror website

Edge loads web pages in IE mode - edge sets ie compatibility

Formation and release of function stack frame
随机推荐
快速排序(非递归)和归并排序
Senior [Software Test Engineer] learning route and necessary knowledge points
three.js第一人称 相机前枪的跟随
Webrtc series - Nomination and ice of 7-ice supplement for network transmission_ Model
How pychart installs packages
EPICS记录参考5 -- 数组模拟输入记录Array Analog Input (aai)
Netease cloud music params and encseckey parameter generation code
Epics record reference 5 -- array analog input recordarray analog input (AAI)
思维的技术:如何破解工作生活中的两难冲突?
IP网络通信的单播、组播和广播
Ad22 Gerber files Click to open the Gerber step interface. Official solutions to problems
neo4j数据库导出
Discussion on streaming media protocol (MPEG2-TS, RTSP, RTP, RTCP, SDP, RTMP, HLS, HDS, HSS, mpeg-dash)
Remapping (STM32)
AD22 gerber files 点开 gerber steup 界面 有问题 官方解决方法
WebRTC系列-网络传输之7-ICE补充之提名(nomination)与ICE_Model
Py2neo basic syntax
Two position relay xjls-8g/220
Unity point light disappears
网易云音乐params和encSecKey参数生成代码