Synchronized HotSpot底层实现-CAS + Unsafe类 + Synchronized锁升级

本文详细介绍了Java中的Synchronized实现原理,包括用户态与内核态的概念、CAS操作的原理与ABA问题、Unsafe类在原子类中的应用。深入探讨了HotSpot虚拟机中synchronized的锁升级过程,从无锁、偏向锁、轻量级锁到重量级锁的变化,以及锁升级的原因。同时,讨论了JVM层面的优化策略,如锁消除和锁粗化,最后对比了synchronized与Lock(CAS)的差异。
摘要由CSDN通过智能技术生成


说明:JVM并没有规定Synchronized应该怎么实现,这里说的是基于HotSpot的实现

用户态与内核态

JDK早期,synchronized 叫做重量级锁, 因为申请锁资源必须通过kernel, 系统调用

;hello.asm
;write(int fd, const void *buffer, size_t nbytes)

section data
    msg db "Hello", 0xA
    len equ $ - msg

section .text
global _start
_start:

    mov edx, len
    mov ecx, msg
    mov ebx, 1 ;文件描述符1 std_out
    mov eax, 4 ;write函数系统调用号 4
    int 0x80

    mov ebx, 0
    mov eax, 1 ;exit函数系统调用号
    int 0x80

CAS


    • Compare And Swap(Set) (Compare And Exchange)又被称为: 自旋 / 自旋锁 / 无锁 (无重量锁)

    • 因为经常配合循环操作,直到完成为止,所以泛指一类操作

    • cas(V, Expected, NewValue) ,变量V,期待值Expected, 修改值NewValue
      if (v == a){
          v = b
      }
      else{
          try again or fail
      }
      
  1. CAS操作得到了CPU的原语支持,也就是说CAS操作是CPU指令级别的操作,它中途是不可能被打断的

  2. ABA问题,也就是原来a=1,之后有一个线程把它改成了 a=2,之后又把它改回成1;对于int类型肯定对结果无伤大雅,但是有一些数据结构不行,比如说对象,这可能会导致错误的结果,

    解决办法:加一个版本号 (AtomicStampedReference),在这个对象做任何修改之前就改一下它的版本号,在if判断的时候连同版本号一起检查,比如版本好递增1。当然基础类型简单值不需要版本号,因为它们对结果没有影响。有影响就加一个版本号

  3. CAS操作根本没有用到锁,就完成了锁的功能,但是它付出的代价就是占用CPU的资源,所以在原子类,轻量级锁等地方用到的都是CAS操作

Unsafe与原子类


  1. 所有的原子类的操作都是使用的Unsafe中的CompareAndSwap方法,这个方法的原理就是上面所说的CAS操作的原理,而这个方法是Unsafe这个类里面的。所以原子类的底层原理就是CAS

  2. unsafe类是用来直接操作JVM里面的内存。比如要修改一个对象的属性,是直接通过偏移量在找到这块内存,直接修改。再比如我们可以调用Unsafe类的allocateMemory来分配指定大小的内存,之前的java可是没有这个功能的。这个只有在c,c++里面有

  3. 这个类了解就好,它里面又很多的方法,在JDK8之前,我们这些普通的用户是不能直接使用这个类,这个类是给那些JDK的作者来使用,我们必须通过反射来使用。但在之后的版本,Unsafe类提供了懒汉式的单例,使得我们可以直接拿到它。

AtomicInteger:

public final int incrementAndGet() {
   
        for (;;) {
   
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

public final boolean compareAndSet(int expect, int update) {
   
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

Unsafe:

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

运用:

package com.mashibing.jol;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class T02_TestUnsafe {
   

    int i = 0;
    private static T02_TestUnsafe t = new T02_TestUnsafe();

    public static void main(String[] args) throws Exception {
   
        //Unsafe unsafe = Unsafe.getUnsafe();

        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值