synchronized

描述

修饰普通方法时锁的是当前对象(this),修饰静态方法时锁的是Class实例。JDK1.6对synchronized优化后,引入了一些锁,并且锁只能升级不能降级。

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

image.png

概念

偏向锁

消除数据在无竞争情况下的同步原语。如果程序中大部分锁总是被多个不同线程访问,那偏向模式就是多余的。

# 启动偏向锁,默认
-XX:+UseBiasedLocking
# 关闭偏向锁优化
-XX:-UseBiasedLocking

轻量级锁

对于绝大部分的锁,在整个同步周期内都是不存在竞争的,主要减少重量级锁的性能损耗。

重量级锁

使用系统互斥量,比较耗资源。

锁消除

锁消除是指虚拟机即时编辑器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享资源竞争的锁进行消除。主要判断依据是逃逸分析的数据支持。如下所示是JDK8反编译,JDK1.5之前是使用StringBuffer进行append操作。StringBuffer每一次append都会同步,但是虚拟机检测到StringBuffer对象不会被别的线程使用,就会将消除所有的同步而直接执行了。

public String concatString(String a, String b, String c) {
    return a + b + c;
}

cfr反编译用--stringbuilder false

java -jar cfr-0.146.jar Demo.class --stringbuilder false
/*
 * Decompiled with CFR 0.146.
 */
package com.redoor.synchronize;

import java.io.PrintStream;

public class Demo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        String s = demo.concatString("lucy", "say", "hello");
        System.out.println(s);
    }

    public String concatString(String a, String b, String c) {
        return new StringBuilder().append(a).append(b).append(c).toString();
    }
}

锁粗化

如果连续的一系列操作都是对同一个对象反复加锁和解锁,那即使没有线程竞争,频繁进行互斥同步操作也会导致性能损耗。如上述append操作,虚拟机检测到这些操作都是对同一个对象加锁,将会把锁同步的范围扩大到整个操作序列的外部。会扩展到第一个append操作之前和最后一个append操作之后,这样只需要加锁一次就可以了。

自旋锁

如果物理机有一个以上的处理器,可以让多个线程同时执行。后面请求锁的线程执行一个忙循环(自旋),不放弃处理器执行时间,看看持有锁的线程是否很快释放锁。自旋锁不能替代阻塞,自旋本身可以避免线程切换。如果上一个线程占有锁的时间很短,自旋等待效果很好。如果占有锁的时间很长,自旋会消耗处理器时间。因此自旋次数超过限度就挂起线程。

自适应自旋锁

自适应自旋锁由前一次在同一个锁上的自旋时间及锁拥有者的运行状态决定。如果同一个对象上,自旋等待刚刚成功获取过锁,并且持有锁的线程正在运行,那么虚拟机会认为这次自旋也很有可能再次成功获取锁,进而它允许自旋等待时间更长。如果对于某个锁,自旋很少成功获取过,那在以后获取这个锁时可能省略掉自旋过程,以避免处理器资源浪费。

引用

https://www.cnblogs.com/butterfly100/p/8786856.html
https://zhuanlan.zhihu.com/p/29866981
http://www.benf.org/other/cfr/stringbuilder-vs-concatenation.html

你可能感兴趣的:(synchronized)