多线程与高并发(二)

Synchronized

使用:

锁this和锁普通方法针对的是对象,锁class和静态方法针对的是class文件
请看我另一篇文章:synchronized的使用

概念:

  1. 可重入:

    • 如果一个同步方法调用另外一个同步方法,有一个方法加了锁,另外一个方法也需要加锁,加的是同一把锁同一个线程,那这个时候申请仍然会得到该对象的锁
    • synchronized的就是锁重入的,比如有一个方法m1是sychronized的,m2也是synchronized的,在m1方法里面调用m2,发现是同一个线程的话,可以直接调用的,不需要去重新获取锁,在举一个例子,比如说父类有一个synchronized的方法,子类重写了这个方法,里面还是会用super调用父类的方法(调用父类是同一把锁),如果synchronized的不支持可重入的话,就会造成死锁
    • 所谓的可重入就是你拿到这把锁之后不停的加锁,加一道就state加一,但锁的还是同一个对象,去一道就state减一
  2. 异常锁:

    • 被synchronized修饰的方法,运行时产生了异常,会出现什么情况?
    • 默认情况下锁会被释放,会被原来的那些个准备拿到这把锁的程序乱入进来,所以在并发处理的过程有异常要多加小心,不然可能会发生不一致的情况
    • 比如:在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时如果异常处理不合适,在第一个线程中抛出异常,其他线程就会进入同步代码区,有可能访问到异常产生时的数据
    • 解决方法:在运行过程中产生异常了,可以用catch把异常捕捉起来,然后让代码继续
  3. 锁升级:

    • 1.6之前,这个synchronized的底层实现是重量级的,重要级到这个synchronized都是要去找操作系统去申请锁的地步,这就会造成synchronized的效率非常低
    • 1.6开始改进,后来有了锁升级的概念
    • 锁级别和过程:
      1. 无锁:创建一个线程,还未去获取锁
      2. 偏向锁:只有一个线程去获取锁的时候,实际上并没有给锁对象加锁,而是在锁对象的头markword上记录这个线程ID
      3. 自旋锁:当有线程去征用锁的话,会先撤销锁,把记录的线程ID撤销,升级为自旋锁,通过CAS竞争,谁先把LR指针放入maekword中,谁先使用,没抢到锁的线程会用一个while循环去获取锁,当达到设定的次数之后会进行锁升级
      4. 重量级锁:默认自旋锁自旋十次之后,升级为重量级锁,重量级锁就是去操作系统那里去申请资源
        在这里插入图片描述
        锁的升级会把信息记录到markword中:
        无锁:markword中后三位001
        偏向锁:后三位101
        自旋锁:后两位00
        重量级锁:后两位10
        在这里插入图片描述
  4. 注意:

    1. 并不是CAS的效率就一定比系统锁要高,这个需要区分实际情况:
      执行时间短(加锁代码),线程数少,用自旋
      执行时间长,线程数多,用系统锁

      原因:CAS会一直自旋争抢锁,占cpu,重量级锁不会去争抢锁,线程待在阻塞队列,由cpu算法调度
    2. synchronized(object)不能用String常量,Integer,Long
    3. 偏向锁和自旋锁是用户态锁,不需要去申请操作系统,偏向锁是延时开启的,默认4秒,可通过jvm参数控制
    4. 重量级锁是内核态,每次会去操作系统申请锁,自旋锁默认10次会升级为重量级锁
    5. 关于锁的信息,大家可以看我之后的文件,AQS
    6. 锁只能升级不能降级
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值