一、并发(concurrent):多线程轮流使用cpu时间片。什么是时间片呢?操作系统层面上,在linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为10ms),window系统最小15ms
1) 单核cpu下,多线程并发实际由cpu时间片执行任务切换串行执行,此时的多线程并发,只是起到任务切换的作用(防止被单线程独占,别的任务加不进来)
由于100ms以内是极短的、无法感知的时间。所以微观串行,宏观上这时也是并行(parallel)的。
2) 对于多核cpu来说,多线程并发第一能够达到并行执行,提高效率(A计算20ms,B10ms,C15ms;串行是45ms,并行只需要20ms);
第二能够起到异步调用(UI线程不必卡住等待耗时任务执行完成)
这就是并发。
二、CAS 实现原理
lock cmpxchg 汇编指令 (lock是几乎所有CPU都支持的一条汇编指令,指的是锁总线)
JDK提供的的轻量级线程安全操作(如自增等),它在无锁的状态下实现了线程安全。
1、juc里面都是cas实现,就是在用户态把问题解决了
2、CAS的第一个问题 ABA问题 版本号可以解决
3、CAS的第二个问题 compareAndSet修改值的那一段时间如果发生被篡改的问题,解决方法是 修改值的时候使用cas(lock cmpxchg)
三、Volitale实现原理
1、对象创建过程
(1)new <T> 堆上 m默认值0
(2)invoke special m=8
(3)astore 把t用指针指向堆内m=8地址
也就是说,存在着对象被创建到一半,没有完成的时间段。
2、DCL单例需不需要volatile ?
需要。thread1半初始化的时候出现 (2)与(3)的指令乱序。导致thread2拿到了乱序后前的m=0的单例对象。
JVM 的规范,保证了volatile修饰的变量不能乱选。
如何做到的呢?JSR内存屏障
SSBarrier LLBarrier
JVM层面(内存屏障) Volaite写 Volaite读
SLBarrier LSBarrier
hotspot实现 lock addl 锁定一条空语句 在多cpu中执行指令时对内存独占使用,
它将当前cpu对应缓存内容刷到内存,并使其他cpu对应缓存失效,其他cpu只能重新去内存中读取
另外lock语句本身就是一把内存屏障,其他指令无法越过它。
3)volatile 禁止乱序执行的方法是使用lock addl的锁总线的方式来实现,它为什么不使用sfence等cpu原语呢
这是因为lock addl大多数cpu都支持,为了达到方便和普及的目的。
JVM规定八种情况必须加屏障 不能指令乱序 happens-before
as if serial 指令乱序对于单线程执行不会有问题
四、Synchronized实现原理
lock cmpxchg 汇编指令
所谓的锁对象 指的就是 把对象头中的锁信息标志(2字节)改为与之对应量级的锁
1、锁膨胀过程:
偏向锁——>轻量级(自旋锁)——>
1)偏向锁指的是由于工程上70%的时候被synchronized修饰的变量只有单线程在跑,所以最开始的状态是偏向锁
2)锁竞争指的是偏向锁被JVM发现出现了第二个线程来访问
3)
2)markwork中另外有31位的hashcode以及gc标志信息
内存布局
markwork (8字节)
对象字节(4字节)
对齐padding