• Java多线程之锁优化策略


    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561264.html 

        锁的优化策略

        编码过程中可采取的锁优化的思路有以下几种:

        1:减少锁持有时间 

             例如:对一个方法加锁,不如对方法中需要同步的几行代码加锁;

        2:减小锁粒度

            例如:ConcurrentHashMap采取对segment加锁而不是整个map加锁,提高并发性;

        3:锁分离 

            根据同步操作的性质,把锁划分为的读锁和写锁,读锁之间不互斥,提高了并发性。

        4:锁粗化 

            这看起来与思路1有冲突,其实不然。思路1是针对一个线程中只有个别地方需要同步,所以把锁加在同步的语句上而不是更大的范围,减少线程持有锁的时间;

            而锁粗化是指:在一个间隔性地需要执行同步语句的线程中,如果在不连续的同步块间频繁加锁解锁是很耗性能的,因此把加锁范围扩大,把这些不连续的同步语句进行一次性加锁解锁。虽然线程持有锁的时间增加了,但是总体来说是优化了的。

        5:锁消除

            锁消除是编译器做的事:根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程(即不会影响线程空间外的数据),那么可以认为这段代码是线程安全的,不必要加锁。

        Java虚拟机中采取的锁优化策略:

           1:偏向锁:锁对象偏向于当前获得它的线程,如果在接下来的没有被其他线程请求,则持有该锁的线程将不再需要进行同步操作(即:持有该锁的线程在接下来的执行中遇到同步块时不再需要lock和unlock了,直接执行即可)。当另一个线程申请该锁时,当前线程的偏向模式才会结束,让出该锁。

           2:轻量级锁:syncrhoized的底层实现是通过监视器monitor来控制的,而monitorenter与monitorexit这两个原语是依赖操作系统互斥(mutex)来实现的。

    互斥会导致线程挂起,并在较短的时间内又需要重新调度回原线程的,较为消耗资源。轻量级锁(Lightweight Locking)利用了CPU原语Compare-And-Swap(CAS,汇编指令CMPXCHG),尝试在进入互斥前,进行补救,减少多线程进入互斥的几率。

            如果偏向锁失败,那么系统会进行轻量级锁的操作,使用CAS操作来尝试加锁。如果轻量级锁失败,才调用系统级别的重量级锁(syncrhoized)来加锁。     

           3:自旋锁:当线程申请锁时,锁被占用,则让当前线程执行一个忙循环(自旋),看看持有锁的线程是否会很快释放锁。如果自旋后还没获得锁,才进入同步阻塞状态;

               3.1:自适应自旋:自旋的线程自旋的时间为同一个锁上一次线程自旋并获得锁的耗时。如果对于这个锁,自旋很少有成功的,就不自旋了,避免浪费CPU资源。

             为了尽量避免使用重量级锁(操作系统层面的互斥),JVM首先会尝试轻量级锁,轻量级锁会尝试使用CAS操作来获得锁,如果轻量级锁获得失败,说明存在竞争。但是也许很快就能获得锁,就会尝试自旋锁,将线程做几个空循环,每次循环时都不断尝试获得锁。如果自旋锁也失败,那么只能升级成重量级锁。

  • 相关阅读:
    vim 常用指令总结
    冥想、反思
    FM(Factorization Machines)模型详解
    机器学习性能指标(ROC、AUC、召回率)
    数据库常用操作(mysql)
    shell命令总结
    Window Function--the function of window function
    Python用Pillow(PIL)进行简单的图像操作
    Pyecharts : plot Graph, Line, Liquid, Parallel
    机器学习方法--分类、回归、聚类
  • 原文地址:https://www.cnblogs.com/ygj0930/p/6561264.html
Copyright © 2020-2023  润新知