并发编程带来的挑战

一、 简述锁升级的流程和原理
为了防止多线程访问共享资源造成线程阻塞的问题,并不会立马对共享资源加重量级锁,使线程进入BLOCKING状态,而是先尝试加偏向锁,在一步步向轻量级锁、重量级锁膨胀的策略,如下图所示:
image.png
**偏向锁:**不存在资源竞争,资源总是由一个线程获取的情况下使用。在对象头存储了当前线程的id.
**轻量级锁:**如果偏向锁被关闭或者已经被其他线程获取,这种情况下抢占同步锁会膨胀到轻量级锁。轻量级锁会通过CAS操作(自旋),把锁对象的标记字段替换为一个指针指向当前线程栈帧中的LockRecord
**重量级锁:**多个线程获取同一个锁的时候,虚拟机就会阻塞未获取到锁的线程,并在目标锁释放的时候唤醒阻塞的线程。对象头存储了指向重量级锁的指针。
总结:
**偏向锁:**无实际竞争,且将来只有第一个申请锁的线程会使用锁。
**轻量级锁:**无实际竞争,多个线程交替使用锁;允许短时间的锁竞争。
**重量级锁:**有实际竞争,且锁竞争时间长。

二、Synchronized的原理
synchronized有三种方式来加锁,分别是:方法锁,对象锁synchronized(this),类锁synchronized(Demo.Class)。其中在方法锁层面可以有如下3种方式:

修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
使用synchronized加锁会从低到高逐步升级, 无锁->偏向锁->轻量级锁->重量级锁

重量级锁通过对象内部的监视器(monitor)实现,一段被synchronized修饰的同步方法或者代码块时,该线程得先获取到synchronized修饰的对象对应的monitor,过程如下
image.png

三、线程是不是越多越好?为什么?
不是,由于硬件资源的限制,线程过多会造成线程阻塞,阻塞或者唤醒一个线程时,都需要操作系统来帮忙,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。

四、wait和notify为什么要加锁
wait方法的语义有两个,一个是释放当前的对象锁、另一个是使得当前线程进入阻塞队列, 而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁。
  而对于notify来说也是一样,它是唤醒一个线程,既然要去唤醒,首先得知道它在哪里?所以就必须要找到这个对象获取到这个对象的锁,然后到这个对象的等待队列中去唤醒一个线程。

作者:https://gper.club/articles/7e7e7f7ff3g5bgc0g69

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值