简介
同步系列, 这是彤哥想了好久的名字, 本来是准备写锁相关的内容, 但是 java 中的 CountDownLatch,Semaphore,CyclicBarrier 这些类又不属于锁, 它们和锁又有很多共同点, 都是为了协同多线程的执行, 都是一种同步器, 所以这里就借用同步来取名字了, 也就是 "同步系列" 的来源.
概览
这一篇的内容会比较多, 大致包含三大主题: java 中的锁, 同步器, 分布式锁, 大致讲的内容如下:
- (1)volatile
- (2)synchronized
(3)AQS 及 Condition
- (4)ReentrantLock
- (5)ReentrantReadWriteLock
- (6)StampedLock
- (7)CountDownLatch
- (8)Semaphore
- (9)CyclicBarrier
- (10)Phaser
(11)MySQL 实现分布式锁
(12)Redis 实现分布式锁
(13)Zookeeper 实现分布锁
这些内容都比较晦涩难懂, 网上也有比较多的资料, 但往往讲得不够透彻, 彤哥会尽量用通俗易懂的语言把这些问题讲清楚.
名词解释
关于锁的名词也有很多, 彤哥大致整理了下, 全部列到这里:
(1) 公平锁 / 非公平锁
公平锁, 是指按照线程申请的顺序获取锁.
非公平锁, 是指不是按照线程申请的顺序获取锁, 有可能后申请的线程反而先获取到锁, 假如先来的线程一直获取不到锁, 会造成锁饥饿现象.
ReentrantLock 中可以通过构造方法指定是否为公平锁, 默认为非公平锁, 非公平锁的优点在于吞吐量大.
synchronized 无法指定为公平锁, 一直都是非公平锁.
(2) 可重入锁
可重入锁, 是指一个线程获取锁之后再尝试获取锁时会自动获取锁, 可重入锁的优点是避免死锁.
ReentrantLock 和 synchronized 都是可重入锁.
(3) 独享锁 / 共享锁
独享锁, 是指锁一次只能被一个线程持有.
共享锁, 是指锁一次可以被多个线程持有.
ReentrantLock 和 synchronized 都是独享锁, ReadWriteLock 的读锁是共享锁, 写锁是独享锁.
(4) 互斥锁 / 读写锁
与独享锁 / 共享锁的概念差不多, 是独享锁 / 共享锁的具体实现.
ReentrantLock 和 synchronized 都是互斥锁
ReadWriteLock 是读写锁
(5) 乐观锁 / 悲观锁
悲观锁, 是指认为对于同一个数据的并发操作必然会发生修改, 即使不会发生修改也这么认为, 所以一定要加锁.
乐观锁, 是指认为对于同一个数据的并发操作不一定会发生修改, 在更新数据的时候, 尝试去更新数据, 如果失败就不断尝试.
悲观锁适用于写操作多的场景, 乐观锁适用于读操作多的场景.
(6) 分段锁
分段锁, 是一种锁的设计思路, 它细化了锁的粒度, 主要运用在 ConcurrentHashMap 中, 实现高效的并发操作, 当操作不需要更新整个数组时, 就只锁数组中的一项就可以了.
(7) 偏向锁 / 轻量级锁 / 重量级锁
这三个锁主要是针对 synchronized 进行优化使用的, 主要是通过对象监视器在对象头中的字段来表明的.
偏向锁, 是指一段同步代码一直被一个线程访问, 那么这个线程会自动获取锁, 降低获取锁的代价.
轻量级锁, 是指当锁是偏向锁时, 被另一个线程所访问, 偏向锁会升级为轻量级锁, 这个线程会通过自旋的方式尝试获取锁, 不会阻塞, 提高性能.
重量级锁, 是指当锁是轻量级锁时, 当自旋的线程自旋了一定的次数后, 还没有获取到锁, 就会进入阻塞状态, 该锁升级为重量级锁, 重量级锁会使其他线程阻塞, 性能降低.
(8) 自旋锁
自旋锁, 是指尝试获取锁的线程不会阻塞, 而是循环的方式不断尝试, 这样的好处是减少线程的上下文切换带来的开锁, 提高性能, 缺点是循环会消耗 CPU.
(9) 监视器锁
synchronized 的实现方式, 使用 monitorenter 和 monitorexit 来实现.
(10)mutex 锁
互斥锁, LockSupport.part() 底层是通过 mutex 实现的.
彩蛋
招募令:
因为彤哥本身工作也比较繁忙, 很难做到日更, 所以这里诚邀广大好友积极投稿, 大家一起学习一起进步.
可在公众号后台给我留言 "投稿", 互加好友详细讨论投稿内容.
当然, 其它问题也可在公众号后台留言, 不管是生活上, 工作上, 心理上还是身体上的, 欢迎叨扰, 留言必回.
来源: https://www.cnblogs.com/tong-yuan/p/Synchronize.html