2020年5月22日 下午4:19
重新认识“锁”这个字:这点非常非常重要
- x锁 == 争抢锁的x规则:
- 我们这里涉及到悲观锁、乐观锁、自旋锁、适应性自旋锁、无锁、偏向锁、轻量级锁、重量级锁、公平锁、非公平锁、可重入锁、不可重入锁、共享锁、排他锁这十几种锁
- 什么什么锁,翻译过来就是:我们目前按什么什么规则进行争抢锁
锁知识的系统讲解与分类
synchronized锁的原理:这个问题要专门拉出来讲,考的人太多
- 涉及到的数据结构:
- 对象头中的:Mark Word(标记字段)Klass Pointer(类型指针)
- Monitor:
- Monitor可以理解为一个同步工具或一种同步机制。说白了就是synchronized是调用Monitor实现的
- synchronized通过Monitor来实现线程同步,Monitor是依赖于底层的操作系统的Mutex Lock(互斥锁)来实现的线程同步
- synchronized最初实现同步的方式
- 阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态转换需要耗费处理器时间。如果同步代码块中的内容过于简单,状态转换消耗的时间有可能比用户代码执行的时间还要长
最最关键、基础的两种锁:
- 【极端】大家来抢,但只有一个人获得操作对象,不论这个人对这个对象进行何种操作,别人都无法获得这个对象,看看都不行
- 【平和】大家都可以来看到这个对象,但是有一点需要大家保证:你看看可以,一旦你想改这个对象,你必须满足一定的要求:
- 这里面又设计了两种场景需求
- 面试必备之乐观锁与悲观锁 - 掘金
- 外加数据的版本号手段:
- 在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功
- 不加版本号,直接根据数据值本身是否变更:
- CAS:compare and swap(比较与交换)
- 但是:
- 会导致ABA 问题,解决ABA我们又要使用版本号
- 循环时间长开销大
- 自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。
- 只能保证一个共享变量的原子操作
- CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效
- 这里面又设计了两种场景需求
- 上面是从人话的角度去切入真实的场景,计算机只不过在模拟我们日常的需求而已。但是,如果我们专业一点说的话:
- 极端 ==> 悲观锁
- 平和 ==> 乐观锁
- 当我们需要在多线程下保护一个对象时,我们如何选择保护它的模式?
- 这个可以理解成第三方保镖公司,这个公司有自己的套餐服务,你可以选择你保护的这个人的等级:有皇家护卫队等级,有退役海报突击队等级,有配枪的不配枪的….
- 这就等同于上面所说的极端、平和等等模式,不同的人我们选择不同的保护等级,保护领导人当然直接上皇家护卫队等级等级,保护你个平民当然随便请个健身教练就行了,这里强调的是适合!
- 这就涉及到乐观锁和悲观锁的使用场景:
- 具体来说:CAS与synchronized的使用情景
- 简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)
