synchronize关键字和线程可见性

synchronize关键字

synchronize 锁定的对象分别为:方法锁、静态代码块锁、静态方法锁,而锁的范围跟锁对象的生命周期息息相关。而锁对象的其实是按照生命周期来判断,分别为对象锁和类锁

  • 类锁: 也就是class类,class类在jvm运行后便加载到了jvm的方法区中,一般情况下类锁的生命周期是跟着jvm的运行产生关系
  • 对象锁: 也就是对象的实例,根据对象的生命周期,如果对象的实例的内存地址

mark word

在hotsport虚拟机中,存储一个对象分为三部分:对象头、对象体、对齐填充。而java的每一个对象都是object的子类,在object对象的底层包含了很多本地的信息,其中包括mark word的信息。mark word记录了锁的相关信息并保存在了对象头中,mark word的大小根据jvm的位数进行动态调整,而mark word在对象头的存储数据图如下
在这里插入图片描述

锁的基本情况

在java1.6之前增加synchronize关键字一般都是直接通过调用系统底层的阻塞来完成的,并且把其他等待线程挂起操作。
在java1.6之后对synchronize进行了优化加入了偏向锁,轻量级锁

  • 偏向锁:偏向锁其实是一种无锁化的操作,适应于只有一个线程访问的时候,通过对象头中记录的threadID和epho来判断当前线程是获取线程的是哪个是否已经偏向,通过CAS(乐观锁)的方式来对threadID进行修改。如果存在多个线程咋进行锁升级->轻量级锁,该情况比较少,可以通过jvm参数关闭偏向锁
  • 轻量级锁:轻量级锁是偏向锁的升级,也是一种无锁化的操作,他通过自旋锁来操作,自旋也就是for循环通过自旋一定的次数或者自适应来判断是否升级锁,自适应是在jvm中判断上次获取锁的自旋的次数来动态决定下次获取锁的次数。如果通过自旋以后还是没有获取锁对象,则进行锁膨胀为->重量级锁,也就是java1.6之前的锁。
  • 重量级锁:重量级锁是通过monitor,每一个java对象都会有一个monitor,当一个线程获取锁以后,会调用monitorenter的指令,在线程完成后调用monitorexit的指令(释放锁),monitor依赖于底层系统的互斥锁来完成的

wait

在monitor中维护了两个队列,一个是synchronize队列,用户存放等待锁的想吃,还有一个是wait队列,当类调用了wait的时候回释放当前锁,然后把当前线程存放到monitor的wait队列中,只有调用了notify的时候才唤醒wait队列的数据,把数据迁移到synchronize队列中去竞争锁。

volatile和HappenBefore

在java层面一般使用volatile来解决可见性和有序性的问题。在java底层提供了四种指令内存屏障:storestore,loadload,storeload,loadstore,在使用volition关键字的时候回使用storeload来使修改的时候在其他线程可见。
happenBefore 是一种规则:

  • 在一个线程中的任何一个操作都应该happenbefore于该线程的任意后续操作之中
  • volatile变量规则,对于volatile关键字修饰的写的操作一定happenbefore于后续volatile变量的读的操作
  • 传递性规则:如果A happenbefore B, B happenbefore C,C happenbefore D,那么A happenbefore D,
  • start规则,在线程start以前的所有操作都happenbefore 与线程执行的所有操作
  • join规则,如果线程A 调用 B.join成功,那么线程b的所有操作都早于线程a从b调用成功之后
  • 监视器规则,对于任何一个获取synchronize锁的线程的所有操作都早于后一个获取synchronize锁的线程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值