Java并发编——Java锁的实现原理

作者: 糖宝_ | 来源:发表于2018-06-09 06:31 被阅读23次

    一、基础概念

    多CPU:一台计算机上多个物理CPU

    多核:一个CPU上多个核心

    超线程技术:一个核心多个执行执行单元

    二、CPU内存架构:

    高度缓存L1、L2、L3:

    4核8线程:

    我刚整理了一套2018最新的0基础入门和进阶教程,无私分享,加Java学习裙 :678-241-563 即可获取,内附:开发工具和安装包,以及系统学习路线图

    这样就存在缓存一致性问题。

    解决缓存一致性问题的方法:总线锁和缓存锁

    (1)总线锁

    这样之后i的值都为2,但是我们期待的结果是i = 3。

    那么总线锁的意思是当CPU1拿到变量处理完的时候CPU2处于阻塞状态,当CPU1处理完之后,CPU2才能进行处理。

    总线锁带来的问题:存在阻塞问题,性能较低。

    (2)缓存锁

    缓存锁只锁定缓存的数据, 不锁定总线。

    CPU1修改完i的值,写回到内存中。此时CPU2嗅探到总线上i的值与本地缓存中i的值不一致,则缓存中i的值失效,CPU2从总线锁上去取i的值,并进行运算。

    缓存一致性:处理器上提供的缓存协议,保证了缓存一致性。

    缓存协议MESI:

    M:modify

    E:execusive

    S:shared

    I :invalid

    E:execusive状态:数据在本地缓存中,切与内存中数据一致;其他的CPU缓存中没有:

    S:shared状态:每个核心的缓存都一样,且与内存一致:

    M和I状态:其中一个核心修改了值,那么其他的核心的缓存失效

    三、Volatile和Synchronized

    Volatile:保证共享变量的可见性

    向处理器发送一条LOCK#使

    1、引起处理器缓存回写到内存中

    2、使其他的处理器缓存失效

    Synchronized:可见性和排他性

    可以修饰方法和代码块,支持重入

    jdk6之前,是重量级锁

    //实例锁:public class App { public synchronized void demo(String param){ synchronized (this){ //实例锁 } } public static void main(String[] args){ App app = new App(); //下面两个代码排队执行 new Thread(()->{ app.demo(Thread.currentThread().getId()+""); }).start(); new Thread(()->{ app.demo(Thread.currentThread().getId()+""); }).start(); }}123456789101112131415161718

    创建两个实例就不行了:

    //实例锁:public class App { public synchronized void demo(String param){ synchronized (this){ //实例锁 } } public static void main(String[] args){ App app = new App(); App app1 = new App(); //下面两个代码排队执行 new Thread(()->{ app.demo(Thread.currentThread().getId()+""); }).start(); new Thread(()->{ app1.demo(Thread.currentThread().getId()+""); }).start(); }}12345678910111213141516171819

    全局锁:对所有实例都可以

    //全局锁:public class App { public synchronized void demo(String param){ synchronized (App.class){ //全局锁 } } public static void main(String[] args){ App app = new App(); //下面两个代码排队执行 new Thread(()->{ app.demo(Thread.currentThread().getId()+""); }).start(); new Thread(()->{ app.demo(Thread.currentThread().getId()+""); }).start(); }}123456789101112131415161718

    锁的转换:

    无锁状态->偏向锁->轻量级锁->重量级锁

    偏向锁:大部分情况下,多线程之间不仅仅不会存在锁竞争,而且还总是由同一个线程获得

    如果多次访问的是同一个线程的话,只需要获取一次锁

    相关文章

      网友评论

        本文标题:Java并发编——Java锁的实现原理

        本文链接:https://www.haomeiwen.com/subject/uaczsftx.html