多线程并发编程之Synchronized原理解析

Synchronized原理解析

synchronized(this) {
    i++;
}

思考这三个问题?

  1. this对象加锁的状态如何记录?
  2. 状态被记录到this对象里面了吗?
  3. 若锁占用,线程挂起;释放锁时,唤醒挂起的线程,是如何做到的?

堆中对象的存储

代码示例:

public class Demo5_main {

    public static void main(String args[]){
        int a = 1;

        Teacher kody = new Teacher();
        kody.stu = new Student();
    }
}

class Teacher{
    String name = "Kody";
    int age = 40;
    boolean gender = true;

    Student stu;
}

class Student{
    String name = "Emily";
    int age = 18;
    boolean gender = false;
}

在JVM中的存储结构

在这里插入图片描述

  1. 方法中定义的局部变量都存放在虚拟机栈中的局部变量表,堆中存放的是具体的值,局部变量表通过引用指向堆中的值。
  2. 对象中除了存放值外,还存放了对象头,对象头指向方法区中具体的类信息,与堆内存中的对象进行绑定
  3. 如果新创建了一个String对象(String str = new String(“abc”)),str在局部变量表中通过引用指向堆内存中的引用,堆中的引用再指向方法区中的字符串常量池。

对象头的概念

对象除了在堆中存储值外,还开辟了一个内存区域来存放对象头。

Class Metadata Address:就是通过这个来指向Class对象的

Array Length:数组对象的长度就存放在这里

Mark Word:用来存放对象锁的信息,长度为32位或64位

Mark Word

在这里插入图片描述

Unlocked : 未锁定

Light-weight locked : 轻量级锁

Heavy-weight locked : 重量级锁

轻量级加锁过程原理分析

在这里插入图片描述

  1. 线程进行锁的争抢,会在线程独占内存开辟一个Lock Record(锁记录空间),会将对象的Mark Word(最开始的未锁定状态 hashcode|age|0),拷贝到Lock Record中
  2. Lock Record 会用**CAS(Hashcode|age|0, Lock record address)**操作对Mark Word进行更改,只有一个线程会成功修改成功,另一个CAS失败,进行自旋
  3. 栈帧中的Lock Record内存中还有个owner,指向堆中对象的Mark Word,Mark Word也会指向这个owner,表示现在哪个线程占有了这把锁
  4. 当自旋达到一定次数,或者这个时候第三个线程又来争抢锁,锁就会升级为重量级锁。(自旋是一个很消耗性能的操作)

重量级锁加锁原理分析

在这里插入图片描述

  1. 重量级锁是对jvm底层的对象监视器(ObjectMonitor)来实现的,ObjectMonitor用C++来实现的
  2. owner :用来存放抢锁成功的线程
  3. entryList:阻塞池,抢锁失败的线程会进入到里面,这里面的线程状态为Blocking
  4. waitSet:等待池,调用wait()方法就会进入到里面,线程状态为waitting进入等待池会释放锁
  5. count:synchronized是一个可重入锁,用来记录重入的次数
  6. 只有拿到对象的锁,才能调用notify()唤醒等待池中的线程,唤醒的线程不一定会拿到锁,所以synchronized是一个非公平锁

通过这个原理我们可以更加深入的理解线程的6种状态,以及调用wait()和notify()方法为何必须要拿到对象的锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值