synchronized 底层原理

我们都知道synchroized可以让线程同步,所谓同步,就是同一时刻,只能有一个线程执行这段代码。

synchronized:

1.锁对象

public class Main {
    
    private Main main;

    public  Main(Main main) {
        this.main = main;
    }
    
    public void method(){
        synchronized(main){
            System.out.println("这是同步代码块---锁当前对象");
        }
    }
}

2.锁方法

   public synchronized void method(){
            System.out.println("同步方法--锁this对象");
    }

3.锁class对象

  public synchronized static void method(){
            System.out.println("同步静态方法--锁当前类的class对象");
    }

那么synchronized到底是锁什么呢,我们都知道synchronized是锁对象头,那么到底是锁什么呢。
我们先来看下java中对象的格式布局,java中都有固定格式的对象头,对象头中有个Mark Word ,64位虚拟中,Mark Word有64个bit。

25bit31bit1bit4bit1bit (偏向锁标识)2bit(锁标志位)
unusedhashCodeunused分带年龄偏向锁标致锁标识位

我们无需关注太多,只需要只知道在对象头中 有2个bit用来标志锁,有1个bit标志是否偏向锁

1bit (偏向锁标识2bit(锁标志位
1:偏向锁01:无锁
0:非偏向锁00:轻量级锁
10:重量级锁
11:GC标记

所以synchronized给对象加锁,就是修改对象锁标志位数值,所有的线程都是根据这个锁标志位的数值进行判断,这个对象是否上锁

那么synchronized锁是如何升级的

在jdk1.6之之前,synchronized只有无锁和重量级锁两个级别,在jdk1.6之后,优化了性能,synchronized锁状态分为无锁、偏向锁、轻量级锁、重量级锁几个状态

  • 无锁: 指没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。
  • 偏向锁: 指当一段同步代码一直被同一个线程所访问时,即不存在多个线程的竞争时,那么该线程在后续访问时便会自动获得锁,从而降低获取锁带来的消耗,即提高性能。
  • 轻量级锁: 指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能
  • 重量级锁: 指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。
用程序测试锁的升级
  <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
  </dependency>
默认情况下新建对象是无锁状态

![public class Main {
    //根据对象输出对象头的64个bit
    public static void main(String\[\] args) {
        Object o=new Object();
        //输出对象头
        String str= ClassLayout.parseInstance(o).toPrintable();
        System.out.println(str);
    }
}](https://img-blog.csdnimg.cn/20201019001615801.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzgxNTg4Mg==,size_16,color_FFFFFF,t_70#pic_center)

输出:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           09 00 00 00 (00001001 00000000 00000000 00000000) (9)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

在这里插入图片描述

偏向锁

默认开启,但是要延迟4秒,可以在创建对象前等待5秒

   public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        Object obj = new Object();
        //开启一个线程,在线程中枷锁
        Thread t1 = new Thread(() -> {
        //使用synchronized 锁obj
            synchronized (obj) { //锁obj对象  偏向锁
                System.out.println("偏向锁状态");
                System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            }
        });
        启动i线程
        t1.start();
    }

结果:

偏向锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           0d 48 ad 15 (00001101 01001000 10101101 00010101) (363677709)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
轻量级锁

接下来在t1 结束后,使用synchronized锁obj对象,由于是t1线程和主线程交替执行,所以进入轻量级锁

    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        Object obj=new Object();
        //开启一个线程,在线程中枷锁
        Thread t1=new Thread(()->{
            //使用synchronized 锁obj
            synchronized (obj){//锁obj对象  偏向锁
                System.out.println("偏向锁状态");
                System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            }
        });
        //启动线程
        t1.start();
        t1.join();
        synchronized (obj){
            System.out.println("轻量级锁状态");
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }

输出:

偏向锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           0d 10 ed 16 (00001101 00010000 11101101 00010110) (384634893)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

轻量级锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           20 f5 27 01 (00100000 11110101 00100111 00000001) (19395872)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
重量级锁

接下来在主线程锁住obj对象之后,等待两秒 模拟重操作,开启线程t2,让t2线程尝试获取obj锁,就进入重量级锁状态

 public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        Object obj = new Object();
        //开启一个线程,在线程中枷锁
        Thread t1 = new Thread(() -> {
            //使用synchronized 锁obj
            synchronized (obj) {//锁obj对象  偏向锁
                System.out.println("偏向锁状态");
                System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            }
        });
        //启动线程
        t1.start();
        t1.join();

        Thread t2 = new Thread(() -> {
            try {
                //等主线程拿到锁
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (obj) {
                System.out.println("重量级锁状态");
                System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            }
        });
        t2.start();//启动线程t2 尝试获取obj的锁
        synchronized (obj) {
            System.out.println("轻量级锁状态");
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            //主线程不要释放锁
            Thread.sleep(2000);
        }
    }

输出:

偏向锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           0d 20 c8 15 (00001101 00100000 11001000 00010101) (365436941)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

轻量级锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           1c fb b4 00 (00011100 11111011 10110100 00000000) (11860764)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

重量级锁状态
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           0e e1 98 02 (00001110 11100001 10011000 00000010) (43573518)
      4     4        (object header)                           70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total


无锁状态偏向锁状态轻量级锁状态重量级锁状态
0(偏向锁标志位)01(锁标志位)101000010

以上就是synchronized锁升级测试。

### 回答1: "synchronized" 关键字的底层原理是基于 Java 的内置锁(Monitor)机制。 Java 中的锁是通过对象的 monitor 实现的,每个对象都有一个对应的 monitor。当线程进入一个对象的 synchronized 代码块时,它会请求该对象的 monitor,如果该 monitor 没有被其他线程占用,则该线程获得该 monitor 并执行代码块,否则该线程阻塞,直到该 monitor 被释放。 通过使用 monitor,Java 可以保证同一时刻只有一个线程能够访问该对象的 synchronized 代码块,从而实现线程同步。 因此,"synchronized" 关键字实现了线程同步的功能,并且可以避免因竞争访问共享资源导致的线程安全问题。 ### 回答2: synchronized是Java中的关键字,用于实现多线程同步。它的底层原理是通过对象的内部锁(也称为监视器锁)来实现线程的互斥访问。 在Java中,每个对象都有一个与之关联的内部锁。当一个线程尝试进入被synchronized修饰的代码块时,它会首先尝试获得该对象的内部锁。如果锁没有被其他线程所占用,那么该线程就会获取到锁,并且进入临界区执行代码。如果锁已经被其他线程所占用,那么该线程就会进入阻塞状态,直到锁被释放。 在synchronized的实现中,锁的状态有两种:被线程占用和未被占用。当一个线程获得锁后,它会将锁的状态设置为已被占用。其他线程在尝试获取该锁时,会发现锁已被占用,它们会进入锁的等待队列中,等待获取锁的线程释放锁。 在Java语言规范中,对synchronized关键字进行了优化,包括偏向锁、轻量级锁和重量级锁三种状态,这样可以在不同场景下提高并发性能。 总结来说,synchronized底层原理是通过对象的内部锁来实现线程的互斥访问。通过获取和释放锁的机制,保证了同一时间只有一个线程能够访问被synchronized修饰的代码块,从而保证了线程安全。这种机制虽然简单,但在多线程编程中起着重要的作用。 ### 回答3: synchronized 是 Java 中用来实现线程同步的关键字。它的底层原理主要是通过对象的监视器锁来实现的。具体来说,Java 中的每个对象都有一个与之相关联的监视器锁,也称为内部锁或互斥锁。 当线程进入一个 synchronized 代码块或方法时,它会尝试获取对象的监视器锁。如果该锁没有被其他线程占用,那么当前线程就可以获取到锁,并进入临界区。如果该锁已经被其他线程占用,则当前线程就会被阻塞,并且进入等待队列。 一旦当前线程进入临界区,它就可以执行 synchronized 代码块或方法中的内容。其他线程如果想要执行该 synchronized 代码块或方法,就必须等待当前线程释放锁。只有当当前线程执行完 synchronized 代码块或方法,且释放了锁,其他线程才有机会获取到锁并执行相应的代码。 synchronized 的原理可以用实例来解释。假设有一个共享资源,例如一个变量,多个线程同时修改该变量的值。如果没有同步机制,可能会导致不可预期的结果。但是当我们使用 synchronized 关键字对修改该变量的代码进行同步,每次只有一个线程能够获取到锁并修改变量的值,这样就保证了线程安全。 总结来说,synchronized 底层原理是通过对象的监视器锁来实现线程之间的同步。它确保了同一时刻只有一个线程能够获取到锁,并且其他线程需要等待锁的释放才能继续执行。这样可以有效地保护共享资源,避免多个线程同时对共享资源进行修改导致的数据不一致性和不可预测性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值