
├── 01 并发编程基础
│ ├── 1-1 课程简介
│ ├── 1-2 什么是并发编程
│ ├── 1-3 并发编程的挑战之频繁的上下文切换
│ ├── 1-4 并发编程的挑战之死锁
│ ├── 1-5 并发编程的挑战之线程安全
│ └── 1-6 并发编程的挑战之资源限制
├── 02 线程基础
│ ├── 2-1 进程与线程的区别
│ ├── 2-2 线程的状态及其相互转换
│ ├── 2-3 创建线程的方式(上)
│ ├── 2-4 创建线程的方式(下)
│ ├── 2-5 线程的挂起跟恢复
│ ├── 2-6 线程的中断操作
│ ├── 2-7 线程的优先级
│ └── 2-8 守护线程
├── 03 线程安全
│ ├── 3-1 什么是线程安全性?
│ ├── 3-2 从字节码角度剖析线程不安全操作
│ ├── 3-3 原子性操作
│ ├── 3-4 深入理解synchronized
│ ├── 3-5 volatile关键字及其使用场景
│ ├── 3-6 单例与线程安全
│ └── 3-7 如何避免线程安全性问题
├── 04 锁机制
│ ├── 4-1 锁的分类
│ ├── 4-2 深入理解Lock接口
│ ├── 4-3 实现属于自己的锁
│ ├── 4-4 AbstractQueuedSynchronizer浅析
│ ├── 4-5 深入剖析ReentrantLock源码之非公平锁的实现
│ ├── 4-6 深入剖析ReentrantLock源码之公平锁的实现
│ ├── 4-7 掌控线程执行顺序之多线程debug
│ ├── 4-8 读写锁特性及ReentrantReadWriteLock的使用
│ ├── 4-9 源码探秘之AQS如何用单一int值表示读写两种状态
│ ├── 4-10 深入剖析ReentrantReadWriteLock之读锁源码实现
│ ├── 4-11 深入剖析ReentrantReadWriteLock之写锁源码实现
│ ├── 4-12 锁降级详解
│ └── 4-13 StampedLock原理及使用
├── 05 线程间通信
│ ├── 5-1 wait、notify、notifyAll
│ ├── 5-2 等待通知经典模型之生产者消费者
│ ├── 5-3 使用管道流进行通信
│ ├── 5-4 Thread.join通信及其源码浅析
│ ├── 5-5 ThreadLocal的使用
│ └── 5-6 Condition的使用
├── 06 原子类
│ ├── 6-1 什么是原子类
│ ├── 6-2 原子更新基本类型
│ ├── 6-3 原子更新数组类型
│ ├── 6-4 原子地更新属性
│ └── 6-5 原子更新引用
├── 07 并发容器
│ ├── 7-1 同步容器与并发容器
│ ├── 7-2 同步容器
│ ├── 7-3 并发容器
│ └── 7-4 LinkedBlockingQueue的使用及其源码探秘
├── 08 并发工具类
│ ├── 8-1 CountDownLatch的使用及其源码探秘
│ ├── 8-2 CyclicBarrier的使用及其源码探秘
│ ├── 8-3 Semaphore的使用及其源码探秘
│ └── 8-4 Exchanger的使用
├── 09 线程池
│ ├── 9-1 为什么要使用线程池?
│ ├── 9-2 创建线程池及其使用
│ ├── 9-3 Future与Callable、FutureTask
│ ├── 9-4 线程池的核心组成部分及其运行机制
│ ├── 9-5 线程池拒绝策略
│ ├── 9-6 Executor框架
│ └── 9-7 线程池的使用建议
├── 10 Java内存模型
│ ├── 10-1 jvm内存模型
│ ├── 10-2 先行发生原则 happens-before
│ └── 10-3 指令重排序
├── 11 多线程实战
│ ├── 11-1 数据同步接口–需求分析
│ ├── 11-2 中间表设计
│ ├── 11-3 基础环境搭建
│ ├── 11-4 生产者代码实现
│ ├── 11-5 消费者编码实现
│ └── 12-1 课程总结