1.Java并发包(JUC)
Java核心库的包
并发包分类
Java.util.concurrency
锁机制类 Locks : Lock, Condition, ReadWriteLock 原子操作类 Atomic : AtomicInteger 线程池相关类 Executer : Future, Callable, Executor 信号量三组工具类 Tools : CountDownLatch, CyclicBarrier, Semaphore 并发集合类 Collections : CopyOnWriteArrayList, ConcurrentMap
2.到底什么是锁
为什么需要显式的 Lock
回忆一下,上节课讲过的, synchronized 可以加锁, wait/notify 可以看做加锁和解锁。 那为什么还需要一个显式的锁呢? synchronized 方式的问题: 1、同步块的阻塞无法中断(不能 Interruptibly) 2、同步块的阻塞无法控制超时(无法自动解锁) 3、同步块无法异步处理锁(即不能立即知道是否可以拿到锁) 4、同步块无法根据条件灵活的加锁解锁(即只能跟同步块范围一致)
更自由的锁
基础接口Lock
Lock示例
读写锁-接口与实现
基础接口-Condition
LockSupport-锁当前线程
用锁的最佳实践
Doug Lea《Java 并发编程:设计原则与模式》一书中, 推荐的三个用锁的最佳实践,它们分别是:
- 永远只在更新对象的成员变量时加锁
- 永远只在访问可变的成员变量时加锁
- 永远不在调用其他对象的方法时加锁
KK总结-最小使用锁: 1、降低锁范围:锁定代码的范围/作用域 2、细分锁粒度:讲一个大锁,拆分成多个小锁
3.并发原子类
Atomic工具类
无锁技术-Atomic工具类
锁与无锁之争
- 思考一下,到底是有锁好,还是无锁好?
什么情况下有锁好 什么情况下无锁好 乐观锁、悲观锁 数据库事务锁 CAS 本质上没有使用锁。 并发压力跟锁性能的关系: 1、压力非常小,性能本身要求就不高; 2、压力一般的情况下,无锁更快,大部分都一次写入; 3、压力非常大时,自旋导致重试过多,资源消耗很大。
LongAdder 对 AtomicLong 的改进
通过分段思想改进原子类, 大家想想,还有哪些是用这个思想? 多路归并的思想:
- 快排
- G1 GC
- ConcurrentHashMap
还记得我们讲的爬山,做一个大项目,都需要加里程碑,也是分段 LongAdder 的改进思路: 1、AtomicInteger 和 AtomicLong 里的 value 是所有 线程竞争读写的热点数据; 2、将单个 value 拆分成跟线程一样多的数组 Cell[]; 3、每个线程写自己的 Cell[i]++,最后对数组求和。
4.并发工具类详解
什么是并发工具类
思考一下: 多个线程之间怎么相互协作? 前面讲到的: 1、wait/notify, 2、Lock/Condition, 可以作为简单的协作机制。 但是更复杂的,需要这些线程 满足某些条件(数量,时间,)。 更复杂的应用场景,比如
- 我们需要控制实际并发访问资源的并发数量
- 我们需要多个线程在某个时间同时开始运行
- 我们需要指定数量线程到达某个状态再继续处理
AQS
Semaphore 信号量
CountDownLatch
CyclicBarrier
CountDownLatch与CyclicBarrier比较
Future/FutureTask/CompletableFuture
CompletableFuture
|