sychronized
对象头中存在MarkWord 和 Class MetaData Address共12个字节
MarkWord: 哈希码,GC分代年龄,锁状态,线程持有的锁,线程ID
Class MetaData Address: 存储对象类型指针,指向类元数据
偏向锁
- 检查到没有人获取到偏向锁的时候,将线程ID存到对象头的MarkWord中,相同线程再次获取锁只需要比较线程id即可
轻量级锁
- 当有线程已经获取锁(偏向锁),其他线程也想获取的时候,偏向锁转为轻量级锁,将MarkWord存到获得锁的线程栈桢中,原MarkWord的位置存一个指向锁记录的指针,锁记录中也会存一个指向锁对象的指针,这样线程和锁对象都存在指向对方的指针,线程就获取了锁。其他线程进行CAS自旋,自旋一定次数获取到锁,那就是获取到轻量级锁,未获取到,就进入阻塞,升级为重量级锁
重量级锁
- 多个线程竞争轻量锁,一个线程获取锁,其他线程自旋无果进入阻塞状态,等待获取锁的线程释放锁之后唤醒阻塞的线程,阻塞——》唤醒,内核态——》用户态的切换,所以是重量级锁
分布式锁:MySQL,Redis,Zk,Etcd
使用第三方锁相比单机JVM锁性能必定降低
多个主机竞争一个商品,性能比单机低,为什么分布式锁性能会降低还要用呢?
- 一个概念,分布式可以提高吞吐量,A商品和B商品的锁是可以并行的,分布式锁是解决分布式的方案实现过程多机竞争商品A的问题,不是为了提高性能
分布式锁和MapReduce就是一个类似的思想,单机分别处理结果汇总,最后竞争一把锁
分布式锁还需要JVM锁吗?
- JVM锁是先保证一个主机内部竞争最后只有一个胜出,最后多主机的竞争数就是主机数,可减少IO,资源浪费
代表锁:MySQL,Redis
Redis问题:
- 如果C1运行一段时间挂了,会死锁
可通过设置超时时间解决问题 - C1拿到偏向锁或轻量级锁之后,C2通过IO发送setnx指令,在做自旋
如果C1迟迟不释放锁,C2就会长时间的自旋,浪费资源 - 如果有大量主机想获取锁,那么会产生大量请求
配置Redis集群,解决单点挂掉问题,分担大量请求 - C1没有挂掉,但是执行超时了
增加额外线程进行续时 - 释放错锁怎么办
锁上加标识UUID - Redis挂了怎么办
配置集群,多机部署或单机保证不挂(有大厂这么用) - 分布式锁主从模式数据同步不及时怎么办
(1)消息队列,发布订阅 + 超时设置+ 额外线程进行超时续时处理(实现很麻烦)
(2)使用RedLock不区分主从节点。每次线程获取锁都要向每个节点发送请求,Redis节点响应过半才能获取锁,这样就不存在数据同步的问题了,同时某个节点挂掉,也不会影响锁的获取 - 如果每个redis节点分别响应一个单独的线程怎么办?
随机重试,再抢一轮,再抢一轮
代表锁:Zk,Etcd
ZK
问题:
- zookeeper的leader节点挂掉怎么办?
选举机制,谁数据新,数据一样看serverid谁大,过半通过 - zookeeper一个节点挂了,会不会丢失锁?
zookeeper存在一个session的概念,哪怕一个节点挂了,其他的节点也会和client快速连接 - 存在临时节点和永久节点
客户端创建path node节点(永久节点)
临时node和session绑定,只要session在,节点就不会删除(断开连接会删除,还有其他情形) - 创建锁会不会重?
获取锁时,C1和C2都会访问leader,有顺序关系,所以像Redis只会获取一个锁 - 如果C1获取锁,C2怎么获取?
zookeeper的watch机制,存在回调函数监测锁,释放就通知客户端,这样就避免了轮询,节省了资源。
创建锁,zookeeper比Redis多了一个同步,两阶段提交的过程,还有一个watch机制,避免了客户端的不断轮询,可理解为Redis的升级版
特点:
也无法保证完全一致,但是正常运行的一致性要高于redis
比较稳定,响应时间波动小
性能会随着并发量上升而下降
每次进行锁操作都要创建若干节点,完成后释放节点,浪费时间
Redis: 红锁,轮询,超时设置,续期
Zookeeper:选举机制,session同步,watch机制
Zookeeper比Redis最强的点在于watch机制,它可以进行超时通知,锁释放通知等,不用像redis一样类CAS自旋不断重试,减少了资源消耗
大厂使用: redis单节点(各部门协调,保证不会出问题),如果很关注锁,就 zookeeper, 马马虎虎就 redis
也可考虑队列,异步,响应式的方式(架构师的级别)
暑期编程PK赛 得CSDN机械键盘等精美礼品!


