首先来了解一下synchronized工作过程也成为了锁膨胀过程:
场景:多个线程对同一变量的操作。
当一个线程进行操作时首先需要进行加锁,但此时并不是真的加锁,而是在对象头里面通过一个标志位进行标记。此时synchronized是偏向锁,在赌没有其他锁来竞争,往往赌还能赌成功。
此时又有一个线程来进行操作时,第二个线程就会尝试加锁,与此同时第一个线程将会立即获取锁,而后面的线程也将尝试真正的加锁,此时涉及到锁竞争,synchronized此时为轻量型锁。
越来越多的线程参与进锁竞争,竞争越来越激烈,自旋锁也慢慢的不容易获取到锁,并且还占用大量的CPU资源,此时synchronized就会继续膨胀为重量型锁,线程争取不到锁之后就会进入阻塞状态,争取到的就会继续工作。
总而言之,synchronized的锁膨胀/锁升级过程是为了更好地适应不同的环境,提高执行的效率。
synchronized还有其他的优化手段:
1.锁清除:初学程序员写代码过程中可能会多次无意义的加锁而导致程序效率变低,JVM如果将该程序判定为不涉及线程安全问题,就会自动将锁去掉。例如单线程变成的情况下,使用StringBuffer将会涉及到无意义的加锁,编译器判定在一个线程内完成,就不会再加锁,而是从编译生成的字节码当中直接去除枷锁过程。
2.锁粗化:锁的粒度代表synchronized所影响的范围。将有一段代码为例子来说明:
stringBuffer.append("hello");
stringBuffer.append("hello");
stringBuffer.append("hello");
stringBuffer.append("hello");
stringBuffer.append("hello");
在这个例子当中,我们无法将锁去掉,每执行一个append就会涉及一次锁操作,将会严重的拖累效率,红色为加锁,绿色为解锁。
减少了不必要的锁竞争。锁的粒度也不是越大越好越小越好,合适最重要