进程内并发(synchronized,volatile,cas)
线程周期
synchronized锁可重用
synchronized底层实现,早期JDK,重量级os实现
synchronized(Object)
这个Object不能用String常量、Integer、Long
- markword记录线程ID(偏向锁)
- 如果线程争用,升级为 自旋锁 (while反复判断能否进入临界区)
- 10次以后,升级为重量级锁(进入等待队列)
自旋锁占用CPU,但不访问OS,在用户态,不在内核态
执行时间短,线程数少,自旋锁
执行时间长,线程多,系统锁
Volatile
保证线程可见性(无法保证原子性即无法替代synchronized关键字)
缓存一致性协议额
MESI
禁止指令重排cpu
- DCL单例
- Double Check Lock
- loadfence原语指令
- storefence原语指令
CAS(无锁优化 自旋,原语级别)
Compare And Swap
使用AtomicInteger实现锁(无锁/乐观锁)
public class _AtomicInteger{ AtomicInteger count = new AtomicInteger(0); void m(){ for(int i = 0; i < 10000; i++){ count.incrementAndGet();// count++ } } }
伪代码
cas(V, Expected, New Value){
if(V == E){
V = New
// try ag or fil
}
}
ABA问题
某个线程执行过程中,先修改integer的值,然后执行具体方法,然后又把integer的值改回来
- 解决方法:加版本号
- A:1 B:2 A:3
- cas(version)
版本号可以通过API AtomicStampedReference
实现
如果是基础类型,没有影响,如果是引用类型,可能线程对有间接寻址的对象做出改变,会导致无法判断
Unsafe(可以和C++一样直接操作内存)
内存管理
包括分配内存、释放内存等
利用copyMemory方法,我们可以实现一个通用的对象拷贝方法,无需再对每一个对象都实现clone方法,当然这通用的方法只能做到对象浅拷贝
非常规的对象实例化
allocateInstance()方法提供了另一种创建实例的途径
通常我们可以用new或者反射来实例化对象,使用allocateInstance()方法可以直接生成对象实例,且无需调用构造方法和其它初始化方法
这在对象反序列化的时候会很有用,能够重建和设置final字段,而不需要调用构造方法
操作类、对象、变量。
这部分包括了staticFieldOffset(静态域偏移)、defineClass(定义类)、defineAnonymousClass(定义匿名类)、ensureClassInitialized(确保类初始化)、objectFieldOffset(对象域偏移)等方法
数组操作
这部分包括了arrayBaseOffset(获取数组第一个元素的偏移地址)、arrayIndexScale(获取数组中元素的增量地址)等方法
arrayBaseOffset与arrayIndexScale配合起来使用,就可以定位数组中每个元素在内存中的位置
多线程同步
包括锁机制、CAS操作等
挂起与恢复
这部分包括了park、unpark等方法
内存屏障
这部分包括了loadFence、storeFence、fullFence等方法。这是在Java 8新引入的,用于定义内存屏障,避免代码重排序
- loadFence() 表示该方法之前的所有load操作在内存屏障之前完成
- storeFence()表示该方法之前的所有store操作在内存屏障之前完成
- fullFence()表示该方法之前的所有load、store操作在内存屏障之前完成
睁开眼,书在面前 闭上眼,书在心里