并发三大特性 原子 有序 可见

本文深入探讨Java内存模型中的原子性、有序性和可见性概念,并详细解释synchronized和volatile关键字如何确保线程安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.原子性(Atomicity):一个操作不能被打断,要么全部执行完毕,要么不执行。
java里头哪些语句是原子性的。真少。原子操作包括:
1)除long和double之外的基本类型的赋值操作
2)所有引用reference的赋值操作
3)java.concurrent.Atomic.* 包中所有类的一切操作。

看见没。只有赋值才是原子操作。什么加减。什么调用函数统统不算。都是有可能被打断的。最常见的就是
i++ i=i+1 还有Object a=new Object(); 这种统统都不符合上面三个原则。 符合的就是a=1 a=null a=b这种完全简单的操作。

long double的赋值为啥不是原子操作呢。因为long和double占用的字节数都是8,也就是64bits。在32位操作系统上对64位的数据的读写要分两步完成,每一步取32位数据。因为太大了。64位操作系统long double的赋值都是原子操作。

有序性
即程序执行的顺序按照代码的先后顺序执行。可是在jvm中很多时候程序并不是按照代码李所写的顺序执行的。
int x=1;
int y=2;
int z=3;
这 三句最后执行的时候 可能 1 3 2 也可能是 2 3 1

看到这里你是不是觉得傻眼了。那我靠,那岂不是乱套了。别急。还有一个保留法则。叫happens-before。这个法子基本保证了你顺序写代码还是靠谱的,然后再加一些关键字可以用来保证顺序,比如volatile 具体啥事happens-before要单独写一篇。后面几个关键字也需要单独写。当然还有as-if-serial语义。也就是你乱排序可以。不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变

可见性:

一个线程对共享变量值的修改,能够及时的被其他线程看到。真抽象。先说哪些是共享变量。。上一篇jmm里头规定了成员变量以及static变量 都是共享变量。这里要引入一个法则,每个共享变量在线程内或者直接就说方法内 读取的时候都是有一个备份x的 比如你直接读取成员变量x。 其实实际操作的时候都是复制一份x。你读取复制x。修改的时候也是复制一份x。修改完同步回去。说着这里估计大家就会脑补了一个可能性。什么可能性线程安全问题。就是你这么操作读的时候跟写的时候因为刚才提到的执行顺序不一致的问题可能导致变量读写不一致,哪怕你是原子操作不可分割。但是还是volatile .synchonized这两个关键字能保证一定的规则。

synchronized
JVM关于synchronized的两条规定:

线程解锁前,必须把共享变量的最新值刷新到主内存;自己脑补下下是在synchronized 啥时候解锁。

线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意,加锁与解锁是同一把锁)。

volatile
对volatile变量写操作时,会在写操作后加入一条store内存屏障指令,将本地内存中的共享变量刷新到主内存;
读的加入一个read屏障指令。这个指令会把工作内存清空。强制从主内存再读一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值