Java多线程_1_Java内存模型_内存模型的3大特性

Java内存模型:

内存分布情况及其关系:

主内存:Java内存模型规定所有的变量都保存在主内存中
工作内存:每个线程都有自己的工作内存,保存了该线程使用到的变量的主内存副本拷贝
主内存与工作内存的关系:
线程对变量的所有操作都必须在自己的工作内存中进行,不能直接读写主内存中的变量
不同线程之间无法直接访问对方工作内存中的变量
线程间变量值的传递均需要通过主内存来完成

内存交互操作:

java内存模型定义了8个操作完成主内存与工作内存的交互操作

1.read: 把变量从主内存读取到工作内存中
2.load: 在read执行后, 把read得到的值存入工作内存中
3.use: 把工作内存中一个变量值传递给执行引擎
4.assign: 把一个执行引擎接收的数据复制给工作内存变量
5.store: 把工作内存中的一个变量的值传送到主内存
6.write: 在store执行后, 把store得到的值放入主内存的变量中
7.lock: 作用于主内存的变量
8.unclock

注:
read-load,store-write必须顺序执行,不需要连续执行(read a,read a,load b,load b),不可单独出现.

不允许一个线程丢弃它最近的assign的操作,即变量在工作内存中改变了之后必须把该变化同步到主内存中

不允许一个线程无原因地把数据从线程的工作内存同步回主内存中

一个新变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化的变量

一个变量在同一时刻只允许一条线程对其lock操作,但lock操作可以被同一条线程执行多次,多次执行lock后,只有执行相同次数的unclock,变量才能解锁

如果对一个变量执行lock操作,将会清空工作内存 中此变量的值,在执行引擎使用这个变量前,需要重新执行load/assign来初始化变量

如果一个变量没被lock锁定,则不允许对它执行unclock,unclock也一致

对变量执行unclock操作之前,必须把此变量同步到主内存中(执行store/write)

原子性:

互斥同步机制:

1.JVM实现的synchronized:同步一个代码块:public void f(){synchronized(this){.......}}
//只能作用于同一个对象, 不同的对象不同进行同步, 例如: 如果同步一个账户,两个人同时操作一个账户,账户加锁即可同步, 对于不同的账户不需要同步, 二者没有任何关系, 也就没有同步这一说法同步一个方法与同步代码块一致只能作用于同一个对象:public synchronized void f(){.....}同步一个类,作用于整个类,两个线程调用同一个类的不同对象也会产生同步:public void f(){synchronized (SynchronizedExample.class){.........}}同步一个静态方法,作用于整个类public synchronized static void f(){....}2.JDK实现的ReentrantLock //java.util.concurrent(J.U.C)包中的锁public class LockTest{private Lock lock = new ReentrantLock();public void f(){lock.lock();try{.......}finally{lock.unlock();//释放锁,避免死锁}}}

上述二者的性能现在大致相同

ReentrantLock与synchronized的区别:
在ReentrantLock中当持有锁的线程长期不释放锁的时候, 正在等待的线程可以选择放弃, 改为处理其他事, synchronized不行
公平锁: 多个线程等待同一个锁, 必须按照申请锁的时间顺序获得锁, synchronized中非公平锁,ReentrantLock也是非公平的, 但也可以是公平的
ReentrantLock可以同时绑定多个Condition对象
注: 除非使用ReentrantLock的高级功能, 否则优先使用synchronized, ReentrantLock不是所有的JDK都支持, 使用synchronized不用担心没释放锁而导致死锁问题, JVM会释放锁

原子性总结

synchronized的修饰对象
修饰代码块:大括号括起来,作用于对象
修饰方法:方法名前使用, 作用于对象在方法内部使用synchronized代码块,与修饰方法时效果是一致的
修饰静态方法:整个静态方法,作用于所有对象
修饰类:类名前添加,作用于所有对象

注:

1.作用于对象时,不同调用对象之间不影响
2.使用synchronized的父类(synchronized不属于方法声明的一部分),子类继承后需要对其方法重新添加synchronized修饰,不然不能使用同步
特点:synchronized:不可中断锁,适用于竞争不激烈,可读性好的场景Lock:可中断锁,多样化同步,竞争激烈时能维持常态Atomic:竞争激烈时能维持常态,比Lock性能好

可见性:

定义: 指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
即: 当共享变量被修改后, 在其他线程修改之前, 会被立马同步到主内存中
导致共享变量在线程中不可见原因:

1.线程交叉执行,交叉过程中,当前线程还未来得及修改主内存值就已被其他线程修改了
2.重排序结合线程交叉执行,指令重排,不具有原子性,导致1.中出现的问题
3.共享变量更新不及时(不能及时从工作内存快速同步到主内存中)

Java多线程的可见性操作
在多线程环境下,一个线程对共享变量的操作对其他线程是不可见的。
Java提供了volatile来保证可见性,当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。
synchronize和Lock都可以保证可见性。synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中, 以此保证可见性。

synchronized与volatile可见性操作细节:

synchronized的可见性:1.线程解锁前(线程执行完同步模块之前),必须把共享变量的最新值刷新到主内存(从工作内存中把值放入主内存)2.线程加锁的时候,必须先清空工作内存中上次存储的共享变量的值,然后再从主内存重新读取最新的值(加锁与解锁是对同一把锁来说)
volatile的可见性:1.对volatile修饰的变量进行写操作的时候,会在写操作之后,加StoreStore屏障指令,将工作内存中变量值刷新到主内存中共享变量2.对volatile修饰的变量进行读操作的时候,会在读操作之前,加StoreLoad屏障指令,从主内存读取共享变量,载入工作内存(也就把以前工作内存存储的值覆盖)
final的可见性:final: 被final修饰的变量在构造函数中被初始化且没有发生this逃逸,其他线程就能看见final

注:
volatile的写操作:
StoreStore屏障禁止volatile指令上面的普通写和下面的volatile写操作重排序
StoreLoad屏障防止volatile写操作与之后volatile读写操作的指令重排
volatile的读操作:
在插入LoadLoad屏障的位置, 禁止该指令前以及该指令后的volatile的读写重排序操作
volatile不具有原子性, 不是线程安全的, 只适合于作为状态标记量, 对变量的写操作不依赖于当前值

有序性:

定义:即程序执行的顺序按照代码的先后顺序执行, 在本线程中观察, 所有的操作都是有序的
需要注意的是:
从其他线程看本线程中会发现所有的操作都是无序的, jvm对每个线程都会进行指令重排, 且重排都会不一样, 在多线程的情况下, 指令重排将会出错, 一般采用volatile/synchronized修饰, 不会出现指令重排, 确保每个时刻都只有一个线程在执行.

先行发生原则:

1.单一线程原则:单个线程内, 程序前面的操作先行发生与后面的操作
2.管程锁定原则:一个unclock操作先行发生于后面对同一个所的lock操作,必须释放锁后,才能对对象重新加锁
3.volatile变量原则:对一个变量的写操作先行发生于后面对这个变量的读的操作
4.线程启动:Thread对象的start操作先行发生于此线程的每一个操作
5.线程加入规则: Thread对象的结束先行发生于join()的返回
6.线程中断原则: 对线程interrupt()的调用先行发生于被中断线程代码检测到的中断时间的发生, 可以通过interrupt检测是否有中断发生
7.对象终结规则: 一个对象的初始化(从构造函数结束开始)先行发生于它的finalize方法的开始
8.传递性: A比B先发生, B比C先发生, 则A比C先发生

上面有错, 还请指出, 如果认为我写的还不错, 还请点个赞, 多多支持一下, O(∩_∩)O~~

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

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

相关文章

requests 获取div_爬虫系列第五篇 使用requests与BeautifulSoup爬取豆瓣图书Top250

上一篇我们学习了BeautifulSoup的基本用法,本节我们使用它来爬取豆瓣图书Top250。一、网页分析我们爬取的网页的url是https://book.douban.com/top250?icnindex-book250-all。首页如图与豆瓣电影Top250差不多,将页面拉到最底部,可以看到分页…

python--socket套接字/TCP

socket套接字/TCP 一 客户端/服务器架构 C/S架构,包括 硬件C/S架构(打印机)软件C/S 架构(web服务)C/S架构的软件(软件属于应用层)是基于网络进行通信的Server端要: 1.力求一直提供服…

uniapp封装网络请求_八张图带你走进“通过一个完美请求封装一个网络模块”

本文提供视频课程讲解,需要的小伙伴可以点赞私信‘’网络模块‘’前往领取学习大纲1、网络模块在应用中的地位1.1当今占统治地位的网络组件OKHttp OkHttp 是一个相对成熟的解决方案,据说 Android4.4 的源码中可以看到 HttpURLConnection 已经替换成 OkHt…

luogu P1046 陶陶摘苹果

二次联通门 : luoguP1046 /*这个题好难.....由苹果树可知这应该是个树结构的题所以很自然的想到了用树链剖分来搞一下连边 最后查询以1为根节点的子树的权值和...从前闲的没事写着玩... */ #include <cstdio> #define Max 3300void read (int &now) {now 0;char wor…

毕业的这0111年

1.2004年&#xff0c;不知道大家对这个时间有没有感觉&#xff0c;那几年我正在读高中&#xff0c;韩寒的《三重门》席卷校园&#xff0c;同样还有郭敬明的《夏至未至》。那时候的我&#xff0c;还挣扎在温饱阶段&#xff0c;我每天吃饭的时候都想上食堂的三楼吃风味&#xff0…

Struts2_4_ActionMap与ValueStack详解_Struct2的EL及常用标签_防止表单数据重复提交

接着Struts2_3_day的讲 注:使用Struts2的< s:debug>< /s:debug>就可获取数据储存的分布图 StrutsPrepareAndExecuteFilter都会创建一个ActionContext和ValueStack对象, 所以Struts2的数据存储分为两类: ActionMap(contextMap)以及ValueStack; ActionMap中都是以m…

python快递代取系统_代取快递的变现方式,校园跑腿的经营范围有多大?

原标题&#xff1a;代取快递的变现方式&#xff0c;校园跑腿的经营范围有多大&#xff1f;进入大学&#xff0c;随着越来越多的学生加入到网购的行列。快递在学校也是堆积成山&#xff0c;高校校园快递市场也日渐红火。但往往带来的也有更多的麻烦&#xff0c;学生取快递时间变…

java 空指针异常之一。 新建的一个对象没有NEW 导致其SET属性时报错

代码&#xff1a; //会报错 Lendbook lbk;//不会报错 Lendbook lbknew Lendbook();//在这里报错lbk.setLenddate(new Date());lbk.setPersoncode(personcode);lbk.setPersonname(personname); 转载于:https://www.cnblogs.com/Ychao/p/6811648.html

我的互助小蜜圈

写在前面 从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群大佬&#xff0c;时刻想着怎样给各位大佬做好服务 &#xff0c;比如我正在溜娃&#xff0c…

设计模式_3_建造者模式

建造者模式(BuilderPattern) 内在的核心问题就是: 使用多个简单对象根据一种组合关系构造一个我们想要的复杂对象, 属于创建型模式 建造者模式的角色关系 建造者模式中总共有两种角色: 1.建造者: 负责建造每个基本组件 2.指挥者: 将建造者建造好的基本组件按照某种组合关系进…

比较两个表格的不同_两表数据的核对,WPS表格似乎更加方便容易

在EXCEL中的两个表格的数据对比&#xff0c;可能使用的方法会采用到查询语句&#xff0c;VBA之类的。显得在使用的过程显得有些复杂。在不经间发现WPS表格的功能处理此类的问题显得就比较的简单的多。查看并标识出分数相同的内容如下面的分数表&#xff0c;选择分数栏的范围&am…

6递归

1 /*2 递归函数:3 函数自己调用自己就叫递归函数4 递归可以实现循环5 递归是神,迭代是人(迭代循环)6 缺点:需要暂存大量的数据,递归次数太多会占用大量内存空间7 8 递归和迭代的区别9 迭代是循环结构 10 递归是选择结…

我的知识小密圈

写在前面从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群朋友&#xff0c;时刻想着怎样给大家做好服务 &#xff0c;比如我正在溜娃&#xff0c;隔断时…

设计模式_4_原型模式(对象的拷贝)

原形模式(PrototypePattern, 创建型模式,创建重复对象且保证性能, 对象的克隆) 通常使用原型模式创建一个原型接口, 用于获取创建对象的克隆, 对于浅拷贝与深拷贝不用纠结, 他们二者的区别就在于重写Clonable的clone方法 浅拷贝与深拷贝 浅拷贝: 直接调用Object的clone pub…

vk_down 每次下翻丙行 c++_笔记本接口不够用?不妨试试这款Type-C拓展坞,给你7个接口用...

随着笔记本电脑越来越轻薄化&#xff0c;已经很难再布局较多的数据接口了&#xff0c;但是在办公等环境下总是需要这些接口来满足需求。就拿小新个人来说&#xff0c;使用的是小米笔记本12.5寸款的&#xff0c;该款笔记本仅有三个接口&#xff0c;分别是全功能 USB-C 接口 x 1、…

学习,才是最好的投资~

推荐语&#xff1a;我因为王小波常说而喜欢的英国哲学家罗素的一句话&#xff1a; 参差多态乃是幸福的本源。正是因为有了多种多样的行业&#xff0c;才使得我们的职业也是多种多样&#xff0c;行行出大牛&#xff01;这个世界天生就注定有人搞互联网的&#xff0c;Linux&#…

第二百四十八节,Bootstrap轮播插件

Bootstrap轮播插件 学习要点&#xff1a; 1.轮播插件 本节课我们主要学习一下 Bootstrap 中的轮播插件。 一&#xff0e;轮播 轮播插件就是将几张同等大小的大图&#xff0c;按照顺序依次播放。 基本实例。 第一步&#xff0c;给轮播器区域div设置一个id给轮播器区域div设置样…

设计模式_4_适配器模式(AdapterPattern, 多个功能的结合)

适配器模式(AdapterPattern, 结构型模式) 用最通俗的讲法就是: 将多个功能相关或不相关的接口( 你需要的接口 )放到同一个实现类里, 构造一个具有多工功能, 多特点的"异类对象" 定义 是作为多个接口之间的桥梁,结合多个独立的接口(将多个类/功能结合在一起,构建出一…

xgboost分类_XGBoost(Extreme Gradient Boosting)

一、XGBoost在Ensemble Learning中的位置机器学习中&#xff0c;有一类算法叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;所谓集成学习&#xff0c;指将多个分类器的预测结果集成起来&#xff0c;作为最终预测结果&#xff0c;它要求每个分类器具备一定的“…

Android技术架构演进与未来

本文阅读大约需15分钟 引言众所周知&#xff0c;Android是谷歌开发的一款基于Linux的开源操作系统&#xff0c;每年迭代一次大版本升级。 小米、华为、OPPO、VIVO、三星等各大厂商对Android原生系统进行二次开发衍生出具有各家特色的系统&#xff08;比如MIUI&#xff09;&…