偏向锁操作流程偏向锁,顾名思义,它会偏向于第一个访问锁的线程,如果在接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步
但是从我们跑的代码输出却看不到偏向锁这个东东。为啥对象实例化出来之后,对象头里是不支持偏向的呢?其实是JVM搞的鬼,JVM虽然默认启用偏向锁,但启动后4秒内并不支持。可以通过-XX:BiasedLockingStartupDelay=0参数将JVM启动后支持偏向锁的延迟时间设置为0,这样就可以看到偏向锁的输出了:
代码也改动一下:
import com.wlf.springcloudgateway.javabean.HelloWorld;
import org.openjdk.jol.info.ClassLayout;import java.util.concurrent.TimeUnit;public class ObjectMarkWord {public static void main(String[] args) throws InterruptedException {// TimeUnit.SECONDS.sleep(5); // 启用偏向锁,要么开启jvm参数-XX:BiasedLockingStartupDelay=0,要么等待5秒// 实例化对象HelloWorld helloWorld = HelloWorld.builder().name("wlf").build();// 1、普通对象,无锁System.out.println("无锁,可偏向:");printfObjMarkWord(helloWorld);// 2、单线程首次加锁,偏向锁System.out.println("偏向锁:");new Thread(() -> {System.out.println("首次偏向:");synchronized (helloWorld) {printfObjMarkWord(helloWorld);}System.out.println("第二次,重偏向:");synchronized (helloWorld) {printfObjMarkWord(helloWorld);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}).start();TimeUnit.SECONDS.sleep(1);// 3、多个线程加锁,膨胀为重量锁System.out.println("重量锁:");for (int i = 0; i < 2; i++) {new Thread(() -> {synchronized (helloWorld) {printfObjMarkWord(helloWorld);}}).start();}}private static void printfObjMarkWord(Object obj) {System.out.println("-------------------------");System.out.println(ClassLayout.parseInstance(obj).toPrintable());System.out.println("-------------------------");}}
输出结果
无锁,可偏向:
-------------------------
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
com.wlf.springcloudgateway.javabean.HelloWorld object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 88 49 1c 17 (10001000 01001001 00011100 00010111) (387729800)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 8 java.lang.String HelloWorld.name (object)
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total-------------------------
偏向锁:
首次偏向:
-------------------------
com.wlf.springcloudgateway.javabean.HelloWorld object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 93 19 (00000101 00000000 10010011 00011001) (429064197)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 88 49 1c 17 (10001000 01001001 00011100 00010111) (387729800)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 8 java.lang.String HelloWorld.name (object)
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total-------------------------
第二次,重偏向:
-------------------------
com.wlf.springcloudgateway.javabean.HelloWorld object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 93 19 (00000101 00000000 10010011 00011001) (429064197)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 88 49 1c 17 (10001000 01001001 00011100 00010111) (387729800)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 8 java.lang.String HelloWorld.name (object)
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total-------------------------
重量锁:
-------------------------
com.wlf.springcloudgateway.javabean.HelloWorld object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 9a 7b c2 02 (10011010 01111011 11000010 00000010) (46300058)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 88 49 1c 17 (10001000 01001001 00011100 00010111) (387729800)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 8 java.lang.String HelloWorld.name (object)
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total-------------------------
-------------------------
com.wlf.springcloudgateway.javabean.HelloWorld object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 9a 7b c2 02 (10011010 01111011 11000010 00000010) (46300058)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 88 49 1c 17 (10001000 01001001 00011100 00010111) (387729800)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 8 java.lang.String HelloWorld.name (object)
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total-------------------------Process finished with exit code 0
我们看到偏向锁在对象实例化后打开了(偏向锁状态为1,锁状态为01),第一次使用锁的时候就是用的偏向锁,持有锁的线程ID被写入对象头中,第二次该线程再次使用偏向锁,线程ID不变。随后我们使用两个其他线程来竞争该锁,偏向锁膨胀为重量锁(锁状态10),原线程ID变更为持有锁的线程指针。
文章转自:https://www.cnblogs.com/wuxun1997/archive/2004/01/13/14098987.html