Java并发编程体系
基础
线程创建方式
- Thread
- Runable
- Callable/Future
- Executor
- 定时任务
线程的状态
- 初始化–就绪–运行中–结束
- wait/notify
- sleep
- synchronized
目的
- 线程安全性
- 线程性能–上下文切换需要消耗
- 优化
线程不安全条件
- 多线程
- 共享变量
- 非原子性操作
需要解决的问题
- 死锁
- 饥饿
- 活锁
三大特性
- 原子性
- 可见性
- 有序性
数据库的四个特性ACID: 原子性,一致性,隔离性,持久性
对象头
- MarkWord
- 年龄
- 线程id
- 锁标志位
- GC标志
- 类型指针
- 数组长度
锁
- 偏向锁
- 轻量级锁、CAS
- 重量锁
- 公平锁
- 非公平锁
- 读写锁
- 锁降级/升级
死锁/活锁
重排序
- 虚拟机的优化手段
- 编译器优化和cpu优化
- as-if-serial原则,无耦合性,前后顺序
happens-before
解决方式
synchronized
- monitorEnter/monitorExit
- 缓存一致性
- 重入锁
- 偏向锁-轻量级锁-重量级锁
- 类、方法、代码块、静态方法
- 原子性、可见性、有序性
volatile
- Java内存模型,
- 保证内存可见性,
- 通过无效化cpu缓存,
- CPU缓存一致性协议MESI(被修改(Modified)、独享的(Exclusive)、共享的(Shared)、无效的(Invalid))
Atomic
- CAS
- AtomicInteger
- LongAdder
Lock接口
容器
Lock–JUC包
Lock接口
- lock
- unlock
- trylock
AbstractQueueSynahronizer接口
- AQS
- 模板方法-设计模式
- 通过 state 控制状态
- 一个基于FIFO队列
- 对外提供 5 个重写方法
- isHeldExclusively 方法表示是否为独占的
- 独占模式下 tryAcquire/tryRelease 获取释放对象
- 共享模式下 tryAcquireShared/tryReleaseShared 获取释放对象
ReentrantLock
- 实现Lock接口
- 可重入锁
- 实现公平锁/非公平锁(通过2个不同内部类实现AQS)
- 使用状态值判断是否已加锁
- CAS
ReentrantWriteReadLock
- 实现Lock接口
- 可重入锁
- 实现公平锁/非公平锁(通过2个不同内部类实现AQS)
- 实现读锁和写锁(通过2个不同内部类实现AQS)
- 里面的state分为2部分(16位+16位)
CountDownLatch
- 开车之前,6个人都绑了安全带,司机才往前开
- 多个线程都count下,另一个线程才继续
- 维护了一个count
- count维护在AQS中
CyclicBarrier
- 跑步之前,所有人准备就绪,然后各个运动员往前跑
- 多线程阻塞,等待这一批线程都到达某个点
- 维护了一个count
- 没用AQS
Semaphore
- 信号量
- 5个人3台机床,其中2人等其他人做完在继续
- 实现公平锁/非公平锁(通过2个不同内部类实现AQS)
- 相当于线程池
Exchange
- 多个线程之间可以交换数据
fork/join
- 可以拆分成多个任务
callable/future
- 带返回值的线程
wait/notify
Condition
- 条件锁
容器
CopyOnWriteList
- 读写分离
- List
- 写在新的数组操作,后面复制数组
ConcurrentLinkedQueue
- 链表
- 队列
- head、tail
- 单数tail=head
- 双数分开
ArrayBlockingQueue
- 阻塞队列
- 生产者消费者
- 通过Condition,来判断不同的等待条件
ConcurrentHashMap
- 1.7使用的是分段锁
- 1.8使用的是数组加链表,next和val使用valatile,保证线程安全性
- 使用CAS操作
线程池
- 参数:核心、最大、过期时间、单位、阻塞模式
- Executor 接口,里面有 execute 方法
- ExecutorService继承Executor
- FixedThreadPool 核心和最大线程数一样
- CachaThreadPool 核心为0,最大为很大
- SingleThreadPool 核心线程为1,
- ScheduledThreadPoolExecutor 定时任务
happens-before
描述了可见性,但是不确保执行顺序
- 代码顺序
- 锁原则,解锁会在二次加锁之前
- volatile原则,防止重排序,
- 传递性
- start规则,线程启动中
- final规则,final修饰字段初始化一定是在构造函数中