java多线程复习之synchronized

JVM中对象分为三部分

对象头:
Mark Word(标记字段):默认存储对象的HashCode,分代年龄和锁标志位信息。它会根据对象的状态复用自己的存储空间,也就是说在运行期间Mark Word里存储的数据会随着锁标志位的变化而变化。
Klass Point(类型指针):对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
**实例变量:**这部分主要是存放类的数据信息,父类的信息。
填充数据:于虚拟机要求对象起始地址必须是8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐。
在这里插入图片描述

Syschronied的作用

sychronied关键字是用来控制线程同步的,在多线程的环境下,synchronized关键字修饰的代码块是不能同时执行的, 可以用来修饰类 方法 代码块 和变量,可以保证原子性,可见性,保证代码的重排序。Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:普通同步方法,锁是当前实例对象;静态同步方法,锁是当前类的class对象;同步方法块,锁是括号里面的对象。
在java6 之前 synchronized是属于重量级锁的,效率低下,因为监视器(monitor)是依赖于底层的操作系统实现的,java线程是映射到操作系统的原生线程上的,如果要挂起或者唤醒一个线程,需要操作系统来帮忙,操作系统要实现线程之间的切换时就需要从用户态切换成内核态,这个切换是很费时间的,在java6 之后java从jvm层面对sychronied锁进行了优化,引用了大量的优化,比如:锁粗化,锁消除,偏向锁,轻量级锁等技术来减少锁的开销。
锁粗化
锁消除
偏向锁
轻量级锁

Syschronied在底层的实现原理

每个java对象都有一个关联的monitor,使用Synchronize的时候,jvm会根据使用的环境找到monitor,根据monitor的状态进行加锁和解锁的判断。如果加锁成功就会成为这个monitor的唯一使用者,在monitor释放前都不能被其他线程获取。同步代码快使用 monitorenter 和 monitorexit 这两个字节码指令获取和释放 monitor。 当执行monitorenter的指令时候,当前线程将试图获取对象锁所对应的moitor所有权,如果对象锁的monitor计数器为0的时候,当前线程就可以获取monitor,并且把monitor的计数器设置为1,并且成功的获取到了对象锁。如果当前对象已经获取到了这个monitor的所有权,那么他也可以选择重入这个monitor,重入的时候monitor的计数器会加1,如果其他线程已经获取了monitor的所有权,那么这个线程将会被阻塞,直到其他线程执行完毕,即monitorexit指令执行,计数器会设置为0;

为啥会有两个monitor呢

主要是为了保证线程在异常的情况下退出的时候,锁没有得到释放,就会造成死锁。所以最后一个monitor是为了保证在异常的情况下,锁可以得到释放,避免死锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值