《Java高并发核心编程 卷2:多线程、锁、JMM、JUC、高并发设计模式》聚焦Java并发编程基础知识,介绍了Java多线程、线程池、内置锁、JMM、CAS、JUC、高并发设计模式等并发编程方面的核心原理和实战知识。
本书共分为10章。第1~2章浅显易懂地剖析多线程、线程池的核心原理和实战使用,揭秘线程安全问题和Java内置锁的核心原理;第3~4章细致地讲解CAS原理与JUC原子类、JMM的核心原理,揭秘CAS操作的弊端和两类规避措施、解密Java如何内存可见性和volatile关键字的底层知识;第5章细致地介绍JUC显示锁的原理和各种显示锁的使用;第6章图文并茂、深入浅出地阐述JUC高并发的基础设施:AQS抽象同步器核心原理;第7章介绍JUC容器类;第8~10章介绍常见的Java高并发设计模式的原理和使用。
封面图
目录
- 前言
- 自序
- 第1章 多线程原理与实战1
- 1.1 两个技术面试故事1
- 1.2 无处不在的进程和线程2
- 1.2.1 进程的基本原理3
- 1.2.2 线程的基本原理5
- 1.2.3 进程与线程的区别8
- 1.3 创建线程的4种方法8
- 1.3.1 Thread类详解8
- 1.3.2 创建一个空线程10
- 1.3.3 线程创建方法一:继承Thread类创建线程类12
- 1.3.4 线程创建方法二:实现Runnable接口创建线程目标类13
- 1.3.5 优雅创建Runnable线程目标类的两种方式16
- 1.3.6 通过实现Runnable接口的方式创建线程目标类的优缺点18
- 1.3.7 线程创建方法三:使用Callable和FutureTask创建线程23
- 1.3.8 线程创建方法四:通过线程池创建线程28
- 1.4 线程的核心原理31
- 1.4.1 线程的调度与时间片31
- 1.4.2 线程的优先级32
- 1.4.3 线程的生命周期35
- 1.4.4 一个线程状态的简单演示案例37
- 1.4.5 使用Jstack工具查看线程状态40
- 1.5 线程的基本操作41
- 1.5.1 线程名称的设置和获取41
- 1.5.2 线程的sleep操作43
- 1.5.3 线程的interrupt操作45
- 1.5.4 线程的join操作48
- 1.5.5 线程的yield操作53
- 1.5.6 线程的daemon操作55
- 1.5.7 线程状态总结61
- 1.6 线程池原理与实战62
- 1.6.1 JUC的线程池架构63
- 1.6.2 Executors的4种快捷创建线程池的方法65
- 1.6.3 线程池的标准创建方式72
- 1.6.4 向线程池提交任务的两种方式73
- 1.6.5 线程池的任务调度流程77
- 1.6.6 ThreadFactory(线程工厂)79
- 1.6.7 任务阻塞队列81
- 1.6.8 调度器的钩子方法82
- 1.6.9 线程池的拒绝策略84
- 1.6.10 线程池的优雅关闭87
- 1.6.11 Executors快捷创建线程池的潜在问题93
- 1.7 确定线程池的线程数97
- 1.7.1 按照任务类型对线程池进行分类97
- 1.7.2 为IO密集型任务确定线程数98
- 1.7.3 为CPU密集型任务确定线程数100
- 1.7.4 为混合型任务确定线程数101
- 1.8 ThreadLocal原理与实战104
- 1.8.1 ThreadLocal的基本使用104
- 1.8.2 ThreadLocal的使用场景107
- 1.8.3 使用ThreadLocal进行线程隔离108
- 1.8.4 使用ThreadLocal进行跨函数数据传递109
- 1.8.5 ThreadLocal内部结构演进110
- 1.8.6 ThreadLocal源码分析111
- 1.8.7 ThreadLocalMap源码分析114
- 1.8.8 ThreadLocal综合使用案例119
- 第2章 Java内置锁的核心原理123
- 2.1 线程安全问题123
- 2.1.1 自增运算不是线程安全的123
- 2.1.2 临界区资源与临界区代码段126
- 2.2 synchronized关键字127
- 2.2.1 synchronized同步方法127
- 2.2.2 synchronized同步块128
- 2.2.3 静态的同步方法130
- 2.3 生产者-消费者问题131
- 2.3.1 生产者-消费者模式131
- 2.3.2 一个线程不安全的实现版本132
- 2.3.3 一个线程安全的实现版本139
- 2.4 Java对象结构与内置锁140
- 2.4.1 Java对象结构141
- 2.4.2 Mark Word的结构信息143
- 2.4.3 使用JOL工具查看对象的布局145
- 2.4.4 大小端问题149
- 2.4.5 无锁、偏向锁、轻量级锁和重量级锁150
- 2.5 偏向锁的原理与实战152
- 2.5.1 偏向锁的核心原理152
- 2.5.2 偏向锁的演示案例152
- 2.5.3 偏向锁的膨胀和撤销156
- 2.6 轻量级锁的原理与实战157
- 2.6.1 轻量级锁的核心原理157
- 2.6.2 轻量级锁的演示案例158
- 2.6.3 轻量级锁的分类161
- 2.6.4 轻量级锁的膨胀162
- 2.7 重量级锁的原理与实战162
- 2.7.1 重量级锁的核心原理162
- 2.7.2 重量级锁的开销165
- 2.7.3 重量级锁的演示案例166
- 2.8 偏向锁、轻量级锁与重量级锁的对比169
- 2.9 线程间通信170
- 2.9.1 线程间通信的定义170
- 2.9.2 低效的线程轮询170
- 2.9.3 wait方法和notify方法的原理171
- 2.9.4 “等待-通知”通信模式演示案例174
- 2.9.5 生产者-消费者之间的线程间通信177
- 2.9.6 需要在synchronized同步块的内部使用wait和notify180
- 第3章 CAS原理与JUC原子类182
- 3.1 什么是CAS182
- 3.1.1 Unsafe类中的CAS方法182
- 3.1.2 使用CAS进行无锁编程185
- 3.1.3 使用无锁编程实现轻量级安全自增186
- 3.1.4 字段偏移量的计算189
- 3.2 JUC原子类191
- 3.2.1 JUC中的Atomic原子操作包191
- 3.2.2 基础原子类AtomicInteger192
- 3.2.3 数组原子类AtomicIntegerArray194
- 3.2.4 AtomicInteger线程安全原理195
- 3.3 对象操作的原子性198
- 3.3.1 引用类型原子类198
- 3.3.2 属性更新原子类200
- 3.4 ABA问题201
- 3.4.1 了解ABA问题201
- 3.4.2 ABA问题解决方案203
- 3.4.3 使用AtomicStampedReference解决ABA问题203
- 3.4.4 使用AtomicMarkableReference解决ABA问题205
- 3.5 提升高并发场景下CAS操作的性能207
- 3.5.1 以空间换时间:LongAdder208
- 3.5.2 LongAdder的原理211
- 3.6 CAS在JDK中的广泛应用218
- 3.6.1 CAS操作的弊端和规避措施218
- 3.6.2 CAS操作在JDK中的应用219
- 第4章 可见性与有序性的原理220
- 4.1 CPU物理缓存结构220
- 4.2 并发编程的三大问题222
- 4.2.1 原子性问题222
- 4.2.2 可见性问题223
- 4.2.3 有序性问题224
- 4.3 硬件层的MESI协议原理227
- 4.3.1 总线锁和缓存锁228
- 4.3.2 MSI协议230
- 4.3.3 MESI协议及RFO请求230
- 4.3.4 volatile的原理234
- 4.4 有序性与内存屏障237
- 4.4.1 重排序237
- 4.4.2 As-if-Serial规则238
- 4.4.3 硬件层面的内存屏障240
- 4.5 JMM详解242
- 4.5.1 什么是Java内存模型243
- 4.5.2 JMM与JVM物理内存的区别244
- 4.5.3 JMM的8个操作246
- 4.5.4 JMM如何解决有序性问题248
- 4.5.5 volatile语义中的内存屏障250
- 4.6 Happens-Before规则251
- 4.6.1 Happens-Before规则介绍252
- 4.6.2 规则1:顺序性规则252
- 4.6.3 规则2:volatile规则252
- 4.6.4 规则3:传递性规则255
- 4.6.5 规则4:监视锁规则255
- 4.6.6 规则5:start()规则256
- 4.6.7 规则6:join()规则257
- 4.7 volatile不具备原子性258
- 4.7.1 volatile变量的自增实例258
- 4.7.2 volatile变量的复合操作不具备原子性的原理260
- 第5章 JUC显式锁的原理与实战262
- 5.1 显式锁262
- 5.1.1 显式锁Lock接口263
- 5.1.2 可重入锁ReentrantLock264
- 5.1.3 使用显式锁的模板代码267
- 5.1.4 基于显式锁进行“等待-通知”方式的线程间通信269
- 5.1.5 LockSupport273
- 5.1.6 显式锁的分类276
- 5.2 悲观锁和乐观锁279
- 5.2.1 悲观锁存在的问题279
- 5.2.2 通过CAS实现乐观锁279
- 5.2.3 不可重入的自旋锁280
- 5.2.4 可重入的自旋锁281
- 5.2.5 CAS可能导致“总线风暴”283
- 5.2.6 CLH自旋锁285
- 5.3 公平锁与非公平锁293
- 5.3.1 非公平锁实战293
- 5.3.2 公平锁实战295
- 5.4 可中断锁与不可中断锁296
- 5.4.1 锁的可中断抢占296
- 5.4.2 死锁的监测与中断298
- 5.5 共享锁与独占锁302
- 5.5.1 独占锁302
- 5.5.2 共享锁Semaphore302
- 5.5.3 共享锁CountDownLatch306
- 5.6 读写锁307
- 5.6.1 读写锁ReentrantReadWriteLock308
- 5.6.2 锁的升级与降级310
- 5.6.3 StampedLock312
- 第6章 AQS抽象同步器的核心原理316
- 6.1 锁与队列的关系316
- 6.2 AQS的核心成员318
- 6.2.1 状态标志位318
- 6.2.2 队列节点类319
- 6.2.3 FIFO双向同步队列321
- 6.2.4 JUC显式锁与AQS的关系322
- 6.2.5 ReentrantLock与AQS的组合关系322
- 6.3 AQS中的模板模式325
- 6.3.1 模板模式325
- 6.3.2 一个模板模式的参考实现326
- 6.3.3 AQS的模板流程329
- 6.3.4 AQS中的钩子方法329
- 6.4 通过AQS实现一把简单的独占锁331
- 6.4.1 简单的独占锁的UML类图331
- 6.4.2 简单的独占锁的实现331
- 6.4.3 SimpleMockLock测试用例333
- 6.5 AQS锁抢占的原理335
- 6.5.1 显式锁抢占的总体流程335
- 6.5.2 AQS模板方法:acquire(arg)336
- 6.5.3 钩子实现:tryAcquire(arg)336
- 6.5.4 直接入队:addWaiter337
- 6.5.5 自旋入队:enq338
- 6.5.6 自旋抢占:acquireQueued()339
- 6.5.7 挂起预判:shouldParkAfterFailedAcquire()340
- 6.5.8 线程挂起:parkAndCheckInterrupt()342
- 6.6 AQS的两个关键点:节点的入队和出队343
- 6.6.1 节点的自旋入队343
- 6.6.2 节点的出队343
- 6.7 AQS锁释放的原理345
- 6.7.1 SimpleMockLock独占锁的释放流程345
- 6.7.2 AQS模板方法:release()345
- 6.7.3 钩子实现:tryRelease()346
- 6.7.4 唤醒后继:unparkSuccessor()346
- 6.8 ReentrantLock的抢锁流程347
- 6.8.1 ReentrantLock非公平锁的抢占流程347
- 6.8.2 非公平锁的同步器子类348
- 6.8.3 非公平抢占的钩子方法:tryAcquire(arg)349
- 6.8.4 ReentrantLock公平锁的抢占流程350
- 6.8.5 公平锁的同步器子类350
- 6.8.6 公平抢占的钩子方法:tryAcquire(arg)351
- 6.8.7 是否有后继节点的判断351
- 6.9 AQS条件队列352
- 6.9.1 Condition基本原理352
- 6.9.2 await()等待方法原理353
- 6.9.3 signal()唤醒方法原理355
- 6.10 AQS的实际应用356
- 第7章 JUC容器类358
- 7.1 线程安全的同步容器类358
- 7.2 JUC高并发容器360
- 7.3 CopyOnWriteArrayList362
- 7.3.1 CopyOnWriteArrayList的使用362
- 7.3.2 CopyOnWriteArrayList的原理364
- 7.3.3 CopyOnWriteArrayList 读取操作366
- 7.3.4 CopyOnWriteArrayList写入操作366
- 7.3.5 CopyOnWriteArrayList的迭代器实现367
- 7.4 BlockingQueue368
- 7.4.1 BlockingQueue的特点368
- 7.4.2 阻塞队列的常用方法368
- 7.4.3 常见的BlockingQueue370
- 7.4.4 ArrayBlockingQueue的基本使用372
- 7.4.5 ArrayBlockingQueue构造器和成员374
- 7.4.6 非阻塞式添加元素:add()、offer()方法的原理376
- 7.4.7 阻塞式添加元素:put()方法的原理378
- 7.4.8 非阻塞式删除元素:poll()方法的原理380
- 7.4.9 阻塞式删除元素:take()方法的原理381
- 7.4.10 peek()直接返回当前队列的头元素382
- 7.5 ConcurrentHashMap383
- 7.5.1 HashMap和HashTable的问题383
- 7.5.2 JDK 1.7版本ConcurrentHashMap的结构384
- 7.5.3 JDK 1.7版本ConcurrentHashMap的核心原理385
- 7.5.4 JDK 1.8版本ConcurrentHashMap的结构393
- 7.5.5 JDK 1.8版本ConcurrentHashMap的核心原理395
- 7.5.6 JDK 1.8版本ConcurrentHashMap的核心源码398
- 第8章 高并发设计模式402
- 8.1 线程安全的单例模式402
- 8.1.1 从饿汉式单例到懒汉式单例402
- 8.1.2 使用内置锁保护懒汉式单例404
- 8.1.3 双重检查锁单例模式404
- 8.1.4 使用双重检查锁+volatile405
- 8.1.5 使用静态内部类实现懒汉式单例模式406
- 8.2 Master-Worker模式407
- 8.2.1 Master-Worker模式的参考实现408
- 8.2.2 Netty中Master-Worker模式的实现413
- 8.2.3 Nginx中Master-Worker模式的实现414
- 8.3 ForkJoin模式415
- 8.3.1 ForkJoin模式的原理415
- 8.3.2 ForkJoin框架416
- 8.3.3 ForkJoin框架使用实战416
- 8.3.4 ForkJoin框架的核心API419
- 8.3.5 工作窃取算法421
- 8.3.6 ForkJoin框架的原理423
- 8.4 生产者-消费者模式423
- 8.5 Future模式424
- 第9章 高并发核心模式之异步回调模式426
- 9.1 从泡茶的案例讲起426
- 9.2 join:异步阻塞之闷葫芦427
- 9.2.1 线程的合并流程427
- 9.2.2 调用join()实现异步泡茶喝427
- 9.2.3 join()方法详解429
- 9.3 FutureTask:异步调用之重武器430
- 9.3.1 通过FutureTask获取异步执行结果的步骤431
- 9.3.2 使用FutureTask实现异步泡茶喝431
- 9.4 异步回调与主动调用434
- 9.5 Guava的异步回调模式435
- 9.5.1 详解FutureCallback435
- 9.5.2 详解ListenableFuture436
- 9.5.3 ListenableFuture异步任务437
- 9.5.4 使用Guava实现泡茶喝的实例438
- 9.5.5 Guava异步回调和Java异步调用的区别442
- 9.6 Netty的异步回调模式442
- 9.6.1 GenericFutureListener接口详解443
- 9.6.2 Netty的Future接口详解443
- 9.6.3 ChannelFuture的使用444
- 9.6.4 Netty的出站和入站异步回调444
- 9.7 异步回调模式小结445
- 第10章 CompletableFuture异步回调446
- 10.1 CompletableFuture详解446
- 10.1.1 CompletableFuture的UML类关系446
- 10.1.2 CompletionStage接口447
- 10.1.3 使用runAsync和supplyAsync创建子任务448
- 10.1.4 设置子任务回调钩子449
- 10.1.5 调用handle()方法统一处理异常和结果451
- 10.1.6 线程池的使用452
- 10.2 异步任务的串行执行453
- 10.2.1 thenApply()方法453
- 10.2.2 thenRun()方法455
- 10.2.3 thenAccept()方法455
- 10.2.4 thenCompose()方法456
- 10.2.5 4个任务串行方法的区别458
- 10.3 异步任务的合并执行458
- 10.3.1 thenCombine()方法458
- 10.3.2 runAfterBoth()方法460
- 10.3.3 thenAcceptBoth()方法461
- 10.3.4 allOf()等待所有的任务结束462
- 10.4 异步任务的选择执行463
- 10.4.1 applyToEither()方法463
- 10.4.2 runAfterEither()方法465
- 10.4.3 acceptEither()方法465
- 10.5 CompletableFuture的综合案例466
- 10.5.1 使用CompletableFuture实现泡茶喝实例466
- 10.5.2 使用CompletableFuture进行多个RPC调用468
- 10.5.3 使用RxJava模拟RPC异步回调469