解释:先读取当前值 a 假设 a = 1,修改后再次读取a的值 ,假如两次一样 则可以修改,不一样不能修改。
应用:java concurrent 包下面的 原子类的操作。如:AtomicInteger
解释: 线程会读取常量池的数据,修改的话会同步到常量池中,因为上面的例子中,子线程睡眠2秒导致主线程执行了 while的内存,所以不会再主动修改a的数值。
加上volatile 关键字后: 相当于每一次获取值是直接从常量池 直接重新拿生成的新的副本。
在单例设计模式中,双重check加锁实现多线程的单例模式,在定义class时,在上volatile防止在指令重排时,对象new 一半的时候返回。
在JVM 有关于对象的内存结构的详细分析,我们知道锁信息是存放在对象头信息中的。
假如现在头信息存储的线程id是1,线程1去获取锁的时候首选读取是1,然修改成1,然后再读一次对象头的线程id还是1,则算获取到锁。线程2也执行类型过程:首先读取线程id是1,然后准备修改为2,修改前再去读一次还是1,则修改成功,这个过程只有一个线程能获取到当前锁。 这个过程叫做自旋锁。
就是jvm给synchronized这个方法做了一些优化,并不是最开始就使用指令把同步代码块锁住,当一段同步代码没有被线程访问的时候,这个时候是处于无锁状态(0),如果这个同步代码块一只被同一个线程访问,那么jvm会给这段代码块加上偏量锁(1),如果不断的有线程进来,那么其他线程开始竞争的时候使用的是cas方式去竞争,这个时候jvm又会把锁升级成自旋锁(00),如果10次都没获取到锁,则进入重量级锁(11),开启指令。
用户态:大部分操作程序叫 用户态,但是一些特殊操作需要调用内核。比如加锁。
AbstractQueuedSynchronizer(以下简写AQS)这个抽象类
sync : 上面说了 是 偏向锁 自旋锁 重量级锁的演变
加锁过程:判断是否有锁,没有 -> 判断是否需要排队,不需要就直接返回。有锁,入队,