美文网首页
synchronized

synchronized

作者: 填坑之路_DK | 来源:发表于2021-03-29 15:46 被阅读0次

java 底层提供的一种同步机制(关键字)

可重入(偏向锁时 当前线程可重入)
异常会释放锁,如果不想被释放,可以catch异常

锁信息只能存储在对象(实例)上

使用对象做锁,一定要加final,对象的属性发生变化不影响锁的使用,但是定义发生改变会导致原来的锁失效 例如重新 o = new Object();

//锁信息存储在调用t1方法的实例上
public synchronized void t1(){}

public  void t2(){
    //锁信息存储在当前实例上
    synchronized(this){ }

    final Object o = new Object();
    //锁信息存储在实例o上
    synchronized(o){}
    
    //锁信息存储在实例Object的对象上,俗称类锁,
    //jvm 加载Object类时,会自动划分一块内存,生成Object类的对象
    synchronized(Object.class){}
}

//锁信息存储在t3方法所处类的对象上,俗称类锁
public synchronized static void t3(){}

实现过程

  1. java代码: 加 synchronize
  2. 字节码层级: monitorenter moniterexit
  3. 执行过程: 自动升级锁
  4. 汇编层级: lock comxchg

锁升级

参考

  • java对象内存模型
    锁信息.png
    新new对象 -> 偏向锁 -> 轻量级锁(无锁 ,自旋锁.自适应锁) ->重量级锁
  1. 无锁: 新new对象
  2. 偏向锁: 第一次拿锁时上的是偏向锁,锁信息为当前线程id号,当前线程可重入
  3. 轻量级锁: 发送任意竞争,撤销偏向锁,上轻量级锁,使用自旋的方式(CAS)竞争锁.
  4. 重量级锁:jdk1.6以下:自旋超过10次,cpu等待核数>1/2,1.6之后加入自适应自旋,jvm自己控制,自动升级(向操作系统申请).

ps:
轻量级锁在自旋拿锁,不停的循环,特别消耗cpu,每个重量级锁都拥有一个队列,等待执行的线程会进入wait状态,不消耗cpu
用户态: 应用程序可以使用的资源
内核态: 使用硬件资源必须通过内核执行,比如拿锁,向显卡写入数据等

锁降级

重量级锁的降级发生于STW(执行垃圾收集算法)阶段,降级对象就是那些仅仅能被VMThread访问而没有其他JavaThread访问的对象。因此没有什么意义,可以认为没有锁降级

锁消除

当jvm发现某有锁对象的引用只能被单一线程使用时(局部变量,栈私有),会自动消除对象内部的锁,例如以下情况就无锁

public void add (String str1,String str2){
    StringBuffer sb = new StringBuffer();
    //会自动消除append方法上的锁
    sb.append(str1).appand(str2);  
}

锁粗化

当jvm发现一连串的操作都对同一对象加锁,jvm就会将加锁的范围粗化到这一连串操作的外部(如while),使得一连串操作只需要加一次锁

private static StringBuffer sb = new StringBuffer();
public static void test (String str){
    sb.clear();
    while(i<100){ //会自动消粗化到while虚幻体外部
        sb.append(str);  
         i++;
    }
    
}

synchronized vs CAS

  1. 在高争用 高耗电的环境下 synchronize 效率更高
  2. 在低争用 低耗电的环境下 CAS效率更高
  3. synchronized 到重量级之后 进入队列 (不消耗CPU)
  4. CAS 等待期间消耗CPU

相关文章

网友评论

      本文标题:synchronized

      本文链接:https://www.haomeiwen.com/subject/zrubhltx.html