• synchronized


    一、synchronized的特性

    ①对于“悲观乐观锁”,是自适应的。
    ②对于“重量轻量锁”,是自适应的。
    ③对于“自旋挂起等待锁”,是自适应的。
    ④不是读写锁
    ⑤是可重入锁
    ⑥是非公平锁。
    初始情况下,synchronized如果预测到当前锁冲突的概率不大,就会以乐观锁的模式来运行(即轻量级锁,基于自旋锁的方式来实现),实际使用过程中,如果发现锁冲突的情况比较多,synchronized会升级为悲观锁(即重量级锁,基于挂起等待锁的方式来实现)。

    二、synchronized的使用

    synchronized要依赖锁对象同时搭配代码块使用。

     Object lock = new Object();
            synchronized (lock) {
                //working
            }
    
    • 1
    • 2
    • 3
    • 4

    三、synchronized的锁机制

    3.1锁升级

    锁升级:无锁→偏向锁→自旋锁→重量级锁。
    锁升级的过程是单向的,是JVM在性能和线程安全之间尽量做出的权衡。
    偏向锁不是真的 “加锁”, 只是给锁的对象头中做一个 “偏向锁的标记”, 记录这个锁属于哪个线程。
    如果后续没有其他线程来竞争该锁, 那么就不用进行其它操作了(避免了加锁解锁的开销)。
    如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了, 很容易识别当前申请锁的线程是不是之前记录的线程), 那就取消原来的偏向锁状态, 进入轻量级锁状态。
    这样就可以既能保证效率又能保证线程安全,偏向锁是“懒汉模式”的一种体现。

    3.2锁消除

    锁消除是一种编译器优化的手段,编译器会自动针对加锁的代码做出判断,如果编译器觉得某个场景下不需要加锁,此时就会把synchronized给优化掉,编译器只会在非常有把握的情况下才会进行锁消除(触发锁消除的概率不是很高)。
    比如StringBuilder不带synchronized,StringBuffer带synchronized,如果是在单线程环境下使用StringBuffer,此时编译器会自动把synchronized优化掉。
    锁消除是在编译阶段触发的,这时还没到运行阶段。偏向锁是发生在运行阶段的事情,如果在编译阶段无法判断这个锁是否需要消除,则这个锁只能保留到运行阶段。

    3.3锁粗化

    锁粗化也是一种编译器优化的手段。
    synchronized代码块里面的代码越多锁的粒度就越粗,代码越少锁的粒度就越细。
    粒度细的锁能够并发执行的逻辑更多,更有利于利用多核cpu资源。但是粒度细的锁被反复进行加锁解锁(涉及反复的锁竞争),可能实际效果还不如粒度粗的锁。
    以下为粒度细的锁:

    for(){
        synchronized(lock){
            n++;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以下为粒度粗的锁:

    synchronized(lock){
        for(){
            n++;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    比如以上锁的粗化避免了一些不必要的锁竞争,提高了程序的执行效率。

  • 相关阅读:
    状态机练习(饮料贩卖机程序设计)8/9
    前列腺特异抗原(PSA)介绍
    蚁群算法ACO求解连续函数问题
    Vue相关面试题(1)
    基于教与学优化的BP神经网络(分类应用) - 附代码
    Python 下载的 11 种姿势,一种比一种高级
    [C语言、C++]数据结构作业:线性表-顺序表的基本操作
    开发问题总结
    重庆建筑模板厂家有哪些?
    星辰天合受邀参加红帽2023中国区合作伙伴大会
  • 原文地址:https://blog.csdn.net/zhanlongsiqu/article/details/133098477