Synchronized总结&锁优化

锁进阶 -- synchronized 的锁优化 介绍 synchronized 锁的优化,包括锁升级、锁消除、锁粗化。 阅读详情

待确认

  1. 轻量级锁相关
    1. 线程启动时,在栈空间初始化锁状态,对象头升级为轻量级锁时,就使用CAS修改对象头的锁状态为栈空间初始化的那个
    2. 怎么重入?1:03 非轻量级锁怎么重入?

1. Synchronized(一)基础总结

  1. 应用场景
    解决多线程安全问题
  2. 方式
    加锁:序列化访问临界资源
  3. Java中的实现
    1. 阻塞式:synchronized、reentrantlock
    2. 非阻塞式:CAS+自旋
  1. 使用
    无论哪种方式,锁住的都是Java对象。
    1. 方法上:acc_synchronized,锁住实例对象/类对象
    2. 代码块中:monitorenter、monitorexit,锁住实例对象
  1. 原理
    1. JVM指令:方法上acc_synchronized;代码块中monitorenter、monitorexit
    2. Monitor/管程:Java锁体系的设计思想,设计的理论基础
      1. MESA模型:入口等待队列(互斥)、多个条件队列(同步、阻塞唤醒机制)
      2. synchronized——简化版MESA模型:Object.wait/notify/notifyAll都依赖于monitor对象。只有重量级锁状态才有Monitor对象。
    1. 重量级锁优化:偏向锁、轻量级锁,都只是更新维护markword头信息中的锁状态,不会创建monitor对象和进行os mutex线程上下文切换
    2. 偏向锁
      不存在竞争,偏向某个线程。 同一个线程进入偏向锁状态的临界区,没有加锁、解锁开销。
    3. 轻量级锁
      线程间存在轻微竞争,比如交替执行,适应于临界区逻辑简单,执行速度快。  
      CAS方式获取锁,即修改markword锁状态信息,将其与线程栈中的lockrecord做双向映射,支持锁重入。
      CAS失败,即进入膨胀为重量级锁的过程。
    4. 重量级锁
      线程间竞争激烈。
      膨胀期间,JVM创建一个Monitor对象,负责维护多线程之间的阻塞唤醒队列,是非公平锁。
      为了避免OS直接挂起、唤醒线程带来的上下文切换的开销,在线程获取不到锁之后,会进行自适应的自旋,最后自旋一定时间后,进入挂起状态。
    5. 加锁/解锁标记
      不同锁在对象头中的标记状态
    6. 实验
      1. synchronized加锁在对象上,对象头的锁状态变化。
      2. 锁升级、锁撤销
    1. 对象内存布局
      JOL测试
  1. 误区
    这部分会在第二部分详细说明。
    1. 关于三种锁状态之间的转换关系
      1. 误区一:锁状态变化是无锁——>偏向锁——>轻量级锁——>重量级
        错误:不存在无锁——>偏向锁,锁状态之间的转换不是按字面顺序的。
      2. 误区二:轻量级锁自旋获取锁失败,会膨胀升级为重量级锁 
        错误:轻量级锁不会自旋,CAS修改markword对象头失败后,就会进入重量级锁膨胀阶段。
      3. 误区三:重量级锁不存在自旋
        错误:重量级锁存在自旋,目的是为了避免直接挂起线程导致的OS线程上下文切换开销。

2. Synchronized锁优化

2.1 偏向锁批量重偏向&批量撤销

从偏向锁的加锁解锁过程中可看出,当只有一个线程反复进入同步块时,偏向锁带来的性能开销基本可以忽略,但是当有其他线程尝试获得锁时,就需要等到safe point时,再将偏向锁撤销为无锁状态或升级为轻量级,会消耗一定的性能,所以在多线程竞争频繁的情况下,偏向锁不仅不能提高性能,还会导致性能下降。于是,就有了批量重偏向与批量撤销的机制。

有用的博客

盘一盘 synchronized (二)—— 偏向锁批量重偏向与批量撤销 - 柠檬五个半 - 博客园

2.1.1 原理

以class为单位,为每个class维护一个偏向锁撤销计数器,每一次该class的对象发生偏向撤销操作时,该计数器+1,当这个值达到重偏向阈值(默认20)时,JVM就认为该class的偏向锁有问题,因此会进行批量重偏向。

当达到重偏向阈值(默认20)后,假设该class计数器继续增长,当其达到批量撤销的阈值后(默认40),JVM就认为该class的使用场景存在多线程竞争,会标记该class为不可偏向,之后,对于该class的锁,直接走轻量级锁的逻辑。

2.1.2 应用场景

  • 批量重偏向(bulk rebias)
    一个线程创建了大量对象并执行了初始的同步操作,后来另一个线程也来将这些对象作为锁对象进行操作,这样会导致大量的偏向锁撤销操作。
  • 批量撤销(bulk revoke)
    在明显多线程竞争剧烈的场景下使用偏向锁是不合适的。

2.1.3 JVM参数

  • -XX:+PrintFlagsFinal
    在项目启动时可输出JVM的默认参数值
  • BiasedLockingBulkRebiasThreshold=20
    偏向锁批量重偏向默认阈值

2.1.4 测试

批量重偏向

/**
 * 偏向锁批量重偏向  -XX:BiasedLockingStartupDelay=4000
 */
@Slf4j
public class BiasedLockingTest {
    public static void main(String[] args) throws InterruptedException {
        //延时产生可偏向对象
        Thread.sleep(5000);
        // 创建一个list,来存放锁对象
        List<Object> list = new ArrayList<>();

        // 线程1
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                // 新建锁对象
                Object lock = new Object();
                synchronized (lock) {
                    list.add(lock);
                }
            }
            try {
                //为了防止JVM线程复用,在创建完对象后,保持线程thead1状态为存活
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thead1").start();

        //睡眠3s钟保证线程thead1创建对象完成
        Thread.sleep(3000);
        log.debug("打印thead1,list中第20个对象的对象头:");
        log.debug((ClassLayout.parseInstance(list.get(19)).toPrintable()));

        // 线程2
        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                Object obj = list.get(i);
                synchronized (obj) {
                    if (i >= 15 && i <= 25) {
                        log.debug("thread2-第" + (i + 1) + "次加锁执行中\t" +
                                ClassLayout.parseInstance(obj).toPrintable());
                    }
                }
                if (i == 17 || i == 19) {
                    log.debug("thread2-第" + (i + 1) + "次释放锁\t" +
                            ClassLayout.parseInstance(obj).toPrintable());
                }
            }
            log.debug("thread2-第" + (1) + "个对象\t" +
                    ClassLayout.parseInstance(list.get(0)).toPrintable());
            log.debug("thread2-第" + (31) + "个对象\t" +
                    ClassLayout.parseInstance(list.get(30)).toPrintable());
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thead2").start();

        //睡眠3s钟保证线程thead2偏向撤销完成
        Thread.sleep(3000);



        // 线程3
        new Thread(() -> {
            Object obj = list.get(21);
            synchronized (obj) {
                log.debug("thread3-执行中\t" +
                        ClassLayout.parseInstance(obj).toPrintable());
            }
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thead3").start();


        LockSupport.park();
    }
}

结果

  1. Object类对象的第20个对象头开始,轻量级锁状态变成重偏向锁,对象头中线程1的ID偏向为线程2的ID;前面的19个对象头,是轻量级锁,符合常规情况
  2. 线程3对第22个对象头进行重偏向测试,发现对象头偏向锁并没有再次重偏向线程3,而是直接变成了轻量级锁,证明对象头只能重偏向一次
  3. 第31个对象头偏向锁ID仍然偏向线程1,因此批量重偏向是懒加载。

批量撤销

@Slf4j
public class BiasedLockingTest2 {
    public static void main(String[] args) throws InterruptedException {
        //延时产生可偏向对象
        Thread.sleep(5000);
        // 创建一个list,来存放锁对象
        List<Object> list = new ArrayList<>();

        // 线程1
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                // 新建锁对象
                Object lock = new Object();
                synchronized (lock) {
                    list.add(lock);
                }
            }
            try {
                //为了防止JVM线程复用,在创建完对象后,保持线程thead1状态为存活
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thead1").start();

        //睡眠3s钟保证线程thead1创建对象完成
        Thread.sleep(3000);
        log.debug("打印thead1,list中第20个对象的对象头:");
        log.debug((ClassLayout.parseInstance(list.get(19)).toPrintable()));

        // 线程2
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                Object obj = list.get(i);
                synchronized (obj) {
                    if (i >= 15 && i <= 21 || i >= 38) {
                        log.debug("thread2-第" + (i + 1) + "次加锁执行中\t" +
                                ClassLayout.parseInstance(obj).toPrintable());
                    }
                }
                if (i == 17 || i == 19) {
                    log.debug("thread2-第" + (i + 1) + "次释放锁\t" +
                            ClassLayout.parseInstance(obj).toPrintable());
                }
            }
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thead2").start();


        Thread.sleep(3000);

        new Thread(() -> {
            for (int i = 20; i < 50; i++) {
                Object lock = list.get(i);
                if (i <= 21 || i >= 35 && i <= 41) {
                    log.debug("thread3-第" + (i + 1) + "次准备加锁\t" +
                            ClassLayout.parseInstance(lock).toPrintable());
                }
                synchronized (lock) {
                    if (i <= 21 || i >= 35 && i <= 41) {
                        log.debug("thread3-第" + (i + 1) + "次加锁执行中\t" +
                                ClassLayout.parseInstance(lock).toPrintable());
                    }
                }
            }
        }, "thread3").start();

        Thread.sleep(3000);
        log.debug("查看新创建的对象");
        log.debug((ClassLayout.parseInstance(new Object()).toPrintable()));

        LockSupport.park();
    }
}

结果

  1. 线程3执行时,导致20-50线程的偏向锁升级为轻量级锁。
  2. 新创建的Object对象的对象头本应该是偏向锁状态,但实际是无锁状态。

2.1.5 总结

  1. 批量重偏向和批量撤销是针对类的优化,和对象无关。
  2. 偏向锁重偏向一次之后不可再次重偏向。
  3. 重偏向是懒加载机制。
  4. 当某个类已经触发批量撤销机制后,JVM会默认当前类产生了严重的问题,剥夺了该类的新实例对象使用偏向锁的权利

2.2 重量级锁自旋

重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。

  • 自旋会占用 CPU 时间,单核 CPU 自旋就是浪费,多核 CPU 自旋才能发挥优势。 
  • 在 Java 6 之后自旋是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋,比较智能。 
  • Java 7 之后不能控制是否开启自旋功能

自旋的目的是为了减少线程挂起的次数,尽量避免直接挂起线程(挂起操作涉及系统调用,存在用户态和内核态切换,这才是重量级锁最大的开销)

2.3 锁粗化

2.3.1 概述

假设一系列的连续操作都会对同一个对象反复加锁及解锁,甚至加锁操作是出现在循环体中的,即使没有出现线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。如果JVM检测到有一连串零碎的操作都是对同一对象的加锁,将会扩大加锁同步的范围(即锁粗化)到整个操作序列的外部。

2.3.2 测试

public class LockCoarseningTest {
    public static void main(String[] args) {
        // 情况1
        StringBuffer buffer = new StringBuffer();
        buffer.append("21321").append("23121");

        // 情况2
        Object lock = new Object();
        synchronized (lock) {
            //do something
        }
        synchronized (lock) {
            //do something
        }
    }
}

上述代码每次调用 buffer.append 方法都需要加锁和解锁,如果JVM检测到有一连串的对同一个对象加锁和解锁的操作,就会将其合并成一次范围更大的加锁和解锁操作,即在第一次append方法时进行加锁,最后一次append方法结束后进行解锁。

2.4 锁消除

2.4.1 概述

锁消除即删除不必要的加锁操作。锁消除是Java虚拟机在JIT编译期间,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间。

2.4.2 测试

/**
 * 锁消除
 * -XX:+EliminateLocks 开启锁消除(jdk8默认开启)
 * -XX:-EliminateLocks 关闭锁消除
 */
public class LockEliminationTest {
    public void append(String str1, String str2) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(str1).append(str2);
    }

    public static void main(String[] args) throws InterruptedException {
        LockEliminationTest demo = new LockEliminationTest();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            demo.append("aaa", "bbb");
        }
        long end = System.currentTimeMillis();
        System.out.println("执行时间:" + (end - start) + " ms");
    }
}

StringBuffer的append是个同步方法,但是append方法中的 StringBuffer 属于一个局部变量,不可能从该方法中逃逸出去,因此其实这过程是线程安全的,可以将锁消除。

测试结果: 关闭锁消除执行时间1813ms 开启锁消除执行时间:1095 ms

2.5 逃逸分析

2.5.1 概述

逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。逃逸分析的基本行为就是分析对象动态作用域。

方法逃逸

当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。

线程逃逸

这个对象甚至可能被其它线程访问到,例如赋值给类变量或可以在其它线程中访问的实例变量。

使用逃逸分析,编译器可以对代码做如下优化:

  1. 同步省略或锁消除(Synchronization Elimination)
    如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。
  2. 将堆分配转化为栈分配(Stack Allocation)
    如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。
  3. 分离对象或标量替换(Scalar Replacement)
    有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

jdk6才开始引入该技术,jdk7开始默认开启逃逸分析。在Java代码运行时,可以通过JVM参数指定是否开启逃逸分析:

-XX:+DoEscapeAnalysis //表示开启逃逸分析 (jdk1.8默认开启) 

-XX:-DoEscapeAnalysis //表示关闭逃逸分析

-XX:+EliminateAllocations //开启标量替换(默认打开) 

2.5.2 测试

/**
 * 进行两种测试
 * 关闭逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来
 * VM运行参数:-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
 * <p>
 * 开启逃逸分析  jdk8默认开启
 * VM运行参数:-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
 * <p>
 * 执行main方法后
 * jps 查看进程
 * jmap -histo 进程ID
 */
@Slf4j
public class EscapeTest {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            alloc();
        }

        long end = System.currentTimeMillis();

        log.info("执行时间:" + (end - start) + " ms");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }

    /**
     * JIT编译时会对代码进行逃逸分析
     * 并不是所有对象存放在堆区,有的一部分存在线程栈空间
     * Ponit没有逃逸
     */
    private static String alloc() {
        Point point = new Point();
        return point.toString();
    }

    /**
     * 同步省略(锁消除)  JIT编译阶段优化,JIT经过逃逸分析之后发现无线程安全问题,就会做锁消除
     */
    public void append(String str1, String str2) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(str1).append(str2);
    }

    /**
     * 标量替换
     */
    private static void test2() {
        Point point = new Point(1, 2);
        System.out.println("point.x=" + point.getX() + "; point.y=" + point.getY());

//        int x=1;
//        int y=2;
//        System.out.println("point.x="+x+"; point.y="+y);
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Point {
    private int x;
    private int y;
}

结果

  1. 关闭逃逸分析

  2. 开启逃逸分析

2.6 总结

2.6.1 三种锁之间的状态转换

  1. 对象锁初始化状态:匿名偏向
  2. 如果对象被一个线程作为锁对象,变为偏向锁状态。
  3. 如果对象锁被2个线程交替使用
    线程1使用锁时为偏向锁状态;线程2使用锁时为轻量级锁状态
  4. 如果对象锁被激烈竞争
    线程1和线程2都是重量级锁

2.6.2 轻量级锁源码流程

2.6.3 重量级锁加锁解锁源码流程

2.6.4 锁重入

  1. 偏向锁
    根据偏向线程ID判断
  2. 轻量级锁
    1. lockrecord
  1. 重量级锁
    1. monitor

gerrit 配置 ----Gitweb集成 此外,为了让用户能够查看任何关于 gitweb 的信息 项目中,用户必须能够阅读所有引用(包括 refs/meta/config,refs/meta/dashboards/*等)。或者,如果Gerrit通过反向代理送达,它可以 为gitweb的链接生成不同的URL(需要的) 在网页服务器上重写为)。Gerrit 代码审查可以管理和生成指向 gitweb 的超链接, 允许用户从Gerrit内容跳转到相同信息, 但由 gitweb 显示。默认为,这是 Linux 发行版上“gitweb”包的常见安装路径。 阅读详情

相关推荐

使用兮克 2.5G 交换机将北京联通 EPON 改为 ODI 猫棒接入

最近入手了兮克2.5G交换机(兮克SKS1200-8GPY1XF),有 8 个 2.5G 电口和 1 个 10G SFP+ 光口;支持多种组网模式,其中一种是支持使用猫棒接入,由路由器拨号后再回接到交换机,这样就可以替换掉光猫了。

啦啦啦啦 la 1万+

初步了解synchronized 的优化过程

初步了解synchronized 的优化过程

yaoyeyi的博客 407

在Wincc8.0的Wincc 3D Control控件中使用3D模型

如果之前没有在Blender中自定义光照,EnableBackground属性选择“是”,Wincc 3D Control会按一个均匀的光照强度渲染。Wincc8.0更新后提供了一个Wincc 3D Control控件来显示3D图像,但是该控件实际体验下来现阶段还存在功能不足、运行不稳定的问题。再把导出的dae文件复制进Wincc项目的GraCS文件夹中,文件名称复制进控件的SceneFile属性里。选择编辑模式,全选模型,点击网格→分离→按材质,分离出不同的部件(不同的部件最好使用不同的材质)。

ghoring的博客 7129

Java多线程基础-15:Java 中 synchronized 的优化操作 -- 锁升级、锁消除、锁粗化

synchronized 的锁优化操作,如何理解锁升级、锁消除、锁粗化

wyd_333的博客 2648

车载仪表-功能点测试大全(超详细,细分可作测试用例)

汽车仪表系统发展经历了机械式、电气化到智能化的演变,目前全液晶仪表渗透率达73.4%。文章详细梳理了仪表功能测试要点,包括UI界面显示一致性、按键响应、FM收音、信号灯显示、USB功能、蓝牙连接、胎压监测、导航系统、WiFi投屏、倒车影像及多媒体播放等关键功能模块的测试标准。特别关注界面切换流畅度、功能稳定性及异常情况处理能力,如投屏状态下是否卡顿、导航中断后能否自动恢复等。测试覆盖了CarPlay、AndroidAuto等主流投屏方案的兼容性验证,确保各类交互场景下的系统可靠性。

weixin_51551002的博客 2063

用C++手把手教你连接SimNow期货模拟盘:从CTP API封装到第一个订单(附完整代码)

本文详细介绍了如何使用C++连接SimNow期货模拟盘,从CTP API的基础架构解析到实现第一个订单的完整流程。内容涵盖CTP API的封装、SimNow环境配置、交易通道实现、行情接收与处理等核心环节,并提供完整代码示例,帮助开发者快速掌握量化交易中的期货模拟盘连接技术。

weixin_27215337的博客 328

jdk1.8对synchronized锁的优化

synchronized 锁的优化:锁的四种状态-无锁,偏向锁、轻量级锁,重量级锁 1、偏向锁:原因是大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁 偏向锁的升级:当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,以后线程1再次获取锁时比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获

常敲代码手不生 4783

innovus:如何在init design之后新增参考库(lib/lef)

如题,在PR过程中经常会遇到这种问题,时序无法收敛,需要新增一套lvt或者hpc的库,怎么办?

m0_61544122的博客 5005

JDK1.8并发之synchronized和Lock

什么是线程安全? 线程安全是指保证多线程环境下共享的、可修改的状态的正确性。 保证线程安全的两个办法: - 封装:将对象的内部状态隐藏、保护起来。 - 不可变:final变量产生了某种程度地不可变(immutable)效果,可以用于保护只读数据。 线程安全需要保证几个基本特性: - 原子性:相关操作不会中途被其他线程干扰,一般通过同步机制实现。 - 可见性:一个线程修改了某个...

哈罗德Android笔记 6472

条件DDPM:Diffusion model的第三个巅峰之作

前言:DDPM从2020年诞生,短短一年的时间,模型上有两个巨大的改进,其中一个就是condition的引入,最近大部分DDPM相关的论文都会讨论这一点,有些文章称之为latent variable。和当年GAN的发展类似,CGAN和DCGAN的出现极大程度上促进了GAN的发扬光大,意义重大。本文基于前面几篇文章继续聊一聊: 从VAE到Diffusion Model_沉迷单车的追风少年-优快云博客 为什么diffusion model扩散模型可以称为score-based models?_沉迷单车的.

沉迷单车的追风少年 1万+

【WRF-Urban】增加动态空间热排放数据以替换人为热排放参数

增加动态空间热排放数据以替换人为热排放参数

WW、forever的博客 1044

JDK8中的锁优化

参考:https://www.cnblogs.com/lkdirk/p/6719248.html LongAdder 类似automicLong, 但是提供了“热点分离”。过程如下:如果并发不激烈,则与automicLong 一样,cas赋值。如果出现并发操作,则使用数组,数组的各元素之和为真实value,让操作分散在数组各个元素上,把并发操作压力分散,一遇到并发就扩容数组,最后达到高效率。一...

m0_38141821的博客 1977

高通开发系列 - System之FOTA/DFOTA包制作和升级

高通开发系列 - System之FOTA/DFOTA包制作和升级

fulinux的博客 4222

【Java多线程】synchronized关键字使用&原理&优化(偏向锁、轻量级锁、重量级锁的介绍)

1.synchronized使用 1.1 修饰一个类 synchronized(ClassName.class) 锁定这个类的所有对象 1.2 加在静态方法上 锁定这个类的所有对象 1.3 加在实例对象上 synchronized(this) 锁住的是实例对象 1.4 加在代码块上或普通方法上 修饰代码块是大括号括起来的范围 2.synchronized原理 2.1 Monitor 2.1.1 对象头 biased_lock代表是不是偏向锁,后面两位(01)代表加锁状态。 2.1.2 Monitor(锁

乾坤未定,你我皆是黑马 299

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

JUC并发编程 synchronized原理进阶 -- 自旋优化 & 偏向锁

1. 自旋优化 重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。 1.1 自旋重试成功的情况 自旋一定是多核CPU下才有意义 1.2 自旋重试失败的情况 1.3 补充: 自旋会占用 CPU 时间,单核 CPU 自旋就是浪费,多核 CPU 自旋才能发挥优势。 在 Java 6 之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋,总

天行健 君子以自强不息,地势坤 君子以厚德载物。 1005

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

synchronized优化原理(轻量级锁、锁膨胀、自旋优化、偏向锁、锁消除)有图解

synchronized优化原理(轻量级锁、锁膨胀、自旋优化、偏向锁、锁消除)

weixin_57034203的博客 992

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

synchronized底层实现原理及锁优化

一、概述 1、synchronized作用 原子性:synchronized保证语句块内操作是原子的 可见性:synchronized保证可见性(通过“在执行unlock之前,必须先把此变量同步回主内存”实现) 有序性:synchronized保证有序性(通过“一个变量在同一时刻只允许一条线程对其进行lock操作”) 2、synchronized的使用 修饰实例方法,对当前实例对象加锁 修饰...

Medlen 7万+

Java 多线程(八)—— 锁策略,synchronized 的优化,JVM 与编译器的锁优化,ReentrantLock,CAS

介绍Java 多线程的锁策略,synchronized 的优化,JVM 与编译器的锁优化,ReentrantLock,CAS

熵减玩家 1万+

Synchronized 锁升级优化

JVM 在 JDK1.6 中引入了分级锁机制来优化 Synchronized,当一个线程获取锁时,首先对象锁将成为一个偏向锁,这样做是为了优化同一线程重复获取导致的用户态与内核态的切换问题;其次如果有多个线程竞争锁资源,锁将会升级为轻量级锁,它适用于在短时间内持有锁,且分锁有交替切换的场景;偏向锁还使用了自旋锁来避免线程用户态与内核态的频繁切换,大大地提高了系统性能;但如果锁竞争太激烈了,那么同步锁将会升级为重量级锁。减少锁竞争,是优化 Synchronized 同步锁的关键。

xuonline4196的博客 1242

synchronized及锁优化

1. synchronized是基于进入与退出监视器对象(Monitor)来实现的,每个java对象都有一个Monitor对象。 2. Monitor依赖于操作系统底层实现 3.开启偏向锁的情况下(默认是开启的),锁状态演化顺序为 偏向锁,轻量级锁,重量级锁 4. 锁的各种优化措施,是为了避免线程从用户态进入到内核态,从而提高效率

他叫阿来 1198

synchronized锁,ReentrantLock 锁

(如程序计数器、栈指针、通用寄存器值等)到内存(通常是内核栈),再加载内核态的上下文。这个过程涉及多次内存读写(内存速度比 CPU 寄存器慢 100 倍以上),且需要严格保证操作的原子性(避免数据错乱),硬件层面的指令执行成本很高。切换时,CPU 必须保存当前用户态的。

chaodddddd的博客 1481

Synchronized锁优化

文章目录Synchronized锁优化(1)引言(2)Java对象的内存布局(3)偏向锁(4)轻量级锁(5)重量级锁 Synchronized锁优化 (1)引言 在JDK1.5之前,synchronized的底层实现都是重量级的,借助操作系统底层实现,也称之为synchronized为重量级锁,在JDK1.5之后,对Synchronized进行了各种优化,实现的原理是锁升级的过程,有了偏向锁、轻量级锁和重量级锁的概念。 (2)Java对象的内存布局 在Java中,创建一个对象后,在JVM中,对象在内存

WYSCODER的博客 1326

【Java并发知识总结 | 第五篇】深入理解Synchronized底层原理(Monitor对象、Synchronized锁优化)

深入理解Synchronized底层原理(Monitor对象、Synchronized锁优化)

踢桃的成长之路 3055

synchronized锁升级之路: 从无锁到偏向锁再到重量级锁,JVM到底在优化什么

/ 创建多个线程制造激烈竞争,触发重量级锁i < 5;i++) {" 持有锁时Mark Word:");try {| 当前状态 | 升级条件 | 目标状态 | 升级成本 || 无锁 | 首次被线程获取 | 偏向锁 | 低(CAS设置ThreadID) || 偏向锁 | 另一线程竞争 | 轻量级锁 | 中等(需安全点+撤销) || 轻量级锁 | 自旋失败/竞争激烈 | 重量级锁 | 高(内核态切换) || 重量级锁 | 无法降级 | 重量级锁 | - |fill:#333;

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 1212

Synchronized锁详解

Synchronized锁详解

lixiangchibang的博客 5091

聊聊synchronized锁优化升级

在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,然后拷贝对象头中的Mark Word复制到锁记录中。如果轻量级锁的更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明多个线程竞争锁。

qq_51967234的博客 952
上一篇: 2022年度总结|2023又得拼搏
下一篇: springboot基础篇—SpringBoot 配置
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值