一、首先谈谈JMM内存模型
-
JMM内存模型规定了线程的工作机理:
即所有的共享变量都存储在主内存,如果线程需要使用,则拿到主内存的副本,然后操作一番,再放到主内存里面
-
提取关键字:JMM内存模型、共享变量、主内存,主内存副本
-
JMM内存模型:JMM决决定一个线程对共享变量的写入何时对对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。这个本地内存并不真实存在,只是JMM的抽象概念。
-
共享变量:类的成员变量就是共享变量,存在于主内存之中
public class Test01{ //没有加volatile关键字修饰 public String share; //成员变量,也是共享变量 public static void main(String[] args){ share = "测试"; } }
-
主内存:所有的线程所共享的,主要包括本地方法区(jdk1.8之后被元空间所替代)和堆
-
主内存副本:线程执行读/写共享变量时在本地内存中创建的副本
-
二、JMM下volatile的作用
上面已经了解了JMM的作用,那么volatile关键字到底起到什么作用呢?
public class Test2{
//使用volatile保证内存可见性
public volatile String share;
public static void main(String[] args){
share = "测试volatile";
}
}
- 作用一:保证内存可见性,使用volatile关键字修饰之后,在编译的时候会主动为变量增加标识:
ACC_VOLATILE
,这样一写多读的场景,可以保证每个线程读到的数据是写入的 - 作用二:禁止指令重排,比如在对使用volatile修饰的变量进行写之前和之后会分别插入一个
StoreStore屏障
和StoreLoad屏障
,这样就可以禁止CPU对指令的重排序越过这些屏障
所以通俗的来说,使用volatile可以保证可见性和有序性,这样能够保证其它内存能拿到最新的变量。但是使用volatile有以下的缺点:
-
缺点一:无法保证原子性,volatile保证的是
单个读取操作是具有原子性的
,比如:int volatile a = 0; //保证了原子性,单次操作 a += 1; //无法保证原子性,不止一次 // a += 1 // a = a+1 // a = 2 //总共执行三次操作
-
缺点二:使用volatile修饰变量后,对该变量的写操作速度会降低
三、synchronized 的作用
保证内存的原子性,可见性,有序性
-
问题一:如何保证内存的原子性,可见性,有序性?
答案就是上锁,synchronized可以用于修饰
普通方法
,静态方法
以及以代码块
的形成出现。原理就是JVM通过进入、退出对象监视器来实现对方法,同步块的同步。编译之后在同步方法调用之前加入一个monitor.enter
指令,在退出方法和异常处插入monitor.exit
指令。在这两条指令没有执行完毕前,其他线程都不能进入,形成了排他性,从而保证了原子性,可见性,有序性。 -
问题二:synchronized上的是什么锁?
锁的类型为对象锁
类型 代码实例 锁住的对象 普通方法 synchronized void test() 当前对象 静态方法 synchronized static void test() 锁的对象是当前类的Class对象 同步块 void fun(){ synchronized(this)} 锁的是()中的对象 -
问题三:synchronized锁的几种形式
-
偏向锁:偏向某一个线程,主要是为了处理同一个线程多次获取同一个锁的情况,比如
锁重入
或者一个线程频繁操作一个线程安全的容器
;但一旦出现线程之间竞争同一个锁,偏向锁就会撤销,升级为轻量级锁 -
轻量级锁:基于CAS操作,线程使用CAS尝试获取锁失败后,进行一段时间的忙等,也就是自旋操作。尝试一段时间仍无法获取锁才会升级为重量级锁。
-
重量级锁:基于底层操作系统实现的,每次获取锁失败都会直接让线程挂起,会带来
用户态
和内核态
的切换,性能开销比较大打一个比方:大家在排队打饭,你有一个专属通道,叫做帅哥美女专属通道,只有你一个人可以自由的同行,这就叫偏向锁
突然有一天,我来了,我也自诩帅哥,所以我盯上了你的通道,但是你还在打饭,然后我就抢过去和你一起打饭,但是这样效率比较低,所以阿姨没问我的时候,我就玩会手机等你,这就叫轻量级锁
突然还有一天,我饿到不行,什么帅哥美女统统滚蛋,就我一个人先打饭,所有阿姨为我服务,给我服务完了再轮到你们,这就叫重量级锁
-
声明:仅作学习记录用途,部分内容来自已有博文