Java并发编程全书概览
2017-03-05 23:32:20 0 举报
《Java并发编程全书》是一本全面深入地探讨Java并发编程的专业书籍。它详细介绍了Java并发编程的基本概念、原理和技巧,包括线程的创建和管理、同步与锁、线程间通信、线程池的使用、并发集合框架等核心内容。此外,书中还深入探讨了Java内存模型、原子操作、无锁编程等高级主题,帮助读者理解和掌握Java并发编程的精髓。无论是初学者还是有一定经验的开发者,都能从这本书中获得宝贵的知识和实践经验。
作者其他创作
大纲/内容
操作数栈
栅栏闭锁信号量FutureTask
当大部分时间都不存在竞争时,采用此锁
开始
高并发、高耗时,synchronized效率高,因为 synchronized 采用等待队列,不消耗CPU
Waiting
3
返回地址
use
1,所有变量都存储在【主内存】中2,每个线程拥有自己的【工作内存】,并且只能访问自己的【工作内存】,保存着从【主内存】中变量的拷贝3,八种操作实现【工作内存】与【主内存】间的【原子操作】:lock 锁定、unlock 解锁、read 读取、load 载入、use 使用、assign 赋值、store 存储、write 写入
Digram form 《HotSpotOverview》
进程 : 用户线程 = 1 : N
线程A
该线程下次进来的时候,就不会再进行同步,直接就可以执行代码
KLT
无锁-->线程A 偏向锁-->线程B 自旋锁(等待)-->轻量级锁 CAS-->重量级锁
KlassPointer
程序一般不直接创建 KLT,而是使用 轻量级进程 Light Weight Process,LWP
HashCode | Age | 0 | 01 | unblocked
java线程
monitorentry、monitorexist
无需 CAS,消除同步原语
执行框架
阻塞队列和生产者-消费者模式
124
串行线程封闭
执行引擎:a` = a`+1
lock 指令、CAS 指令
14
工作内存
监视器锁规则
锁
Java线程的实现方式
禁止JVM对指令重排序优化
对象头.MarkWord.标志位 = 00
锁消除
抢占式调度
不满足Happen-Before 规则的操作
堆内存
read 读取、load 载入、use 使用、assign 赋值、store 存储、write 写入
LWP
对象
拷贝 MW
UT
传递性
01:未被锁定
依赖OS的线程实现
LWP模型
synchronized
构造器先执行,才到 finalize()
轻量级进程 : 内核线程 = 1 : 1
ThreadSafe
Padding
CPU
Monitor address | 10 | Heavy-weight locked
锁粗化
有序性
CAS 加锁和解锁 - 每个线程建立自己的LockRecord,然后通过CAS去争用 MarkWord,竞争N次(默认10次)后,自动升级成重量级锁
HashCode | Age | 00
15
访问同步块
技术
无限期等待:等别人叫醒
save--><--load
123
自旋锁不是锁,而是等待!
data
lock
Runnable
CAS加锁
识别
9
5
CAS 解锁
使用内核线程实现Kernel-Level Thread,KLT
源代码级别保证多操作的原子性
原子性
GUI程序
Timed Waiting
MarkWord
主内存Main Memory
并发程序的测试
P
用户进程自己实现线程(创建、调度)
终结器规则
线程结束规则
load
禁止指令重排序
截停
New
协同式调度
11
JMM
Lock record address | 00 | Light-weight locked
10:重量级锁
低并发、低耗时,Lock 效率高,因为CAS循环等待,很耗CPU
lock 锁定、unlock 解锁
run()结束
同步工具
性能↑
中断事件->Thread.interrupter()->程序检测到此事件
同个monitor上必须先unlock,然后才能让别的线程lock
指向栈中锁记录
所以让来访的线程执行一个空循环,这叫自旋锁
windows有10个优先级
如果操作A先于B,B先于C,那么A必须先于C
12
双端队列与工作密取
使用用户线程实现User Thread,UT
证明获取到锁
synchronized、Lock
当前方法的栈帧
volatile规则
Monitor address | 10
10
lock:lock前,一定是清空了工作内存中副本的值unlock:unlock前,必须把工作内存中变量的值 store->write到主内存read--load :一定是顺序的,但不是连续的,允许插入其他指令store--write:同上
原子变量
依赖OS的调度器
重量级锁
隐藏迭代器
final
start()
对象的组合
6
线程启动规则
13
程序次序规则
锁记录(存MarkWord拷贝)
ConcurrentHashMap
CPU层
用 CAS 把对象头.markword改成指针
解锁
刚开始发现对象未被锁定,然后就标记MarkWord为偏向锁
避免活跃性故障
-主要目标:定义程序中各个变量的访问规则
任务
轻量级锁
编译器根据什么规则来允许CPU执行时使用重排序?
响应
字节码指令级别保证多操作的原子性
伸缩性↑
store
JMM三大特性
wait()join()
额外的原子Map操作
4
对象头.MarkWord.标志位 = 01
比如一个循环中出现的同步块,就会频繁加锁释放锁,这时候可以将锁范围扩大到整个循环体
线程池
一般对象的锁定状态都维持很短时间,为此而将前来访问的线程挂起未免太耗时
指令重排序
int a = 1; int b = a;
提升单线程子系统
lock、unlock-锁升级
Thead ID | Age | 1 | 01 | Biased/biasable
volatile 执行原理
Java内存模型 JMM
write
容器
如果获取锁失败,则线程被挂起,进入等待队列
00:被锁定轻量级锁
可见性
真正的锁,由CPU控制,特殊的CPU指令来完成
如果是多线程竞争
volatile
中断规则
用户线程 : 轻量级进程= N : M
Running
java语言层
单个原子操作
Thread.start()必须先于该线程的所有操作执行
如果CAS成功
unlock
HashCode | Age | 01
CopyOnWriteArrayList
mutex
2
字节码层
动态链接
Terminated
依赖逃逸分析结果,如果发现对象不会被其他线程共享,则消除加在其上面的同步锁
16
monitorenter、moniterexit
虚拟机使用的指令保证多操作操作的原子性
显示锁
指令重排序:多核CPU是流水线(假设是4级)执行指令的:取址->译码->执行->写回源代码:int a = 1;int b = 2;执行时:可能先执行a = 1;再执行b = 2;mov eax 1; // 将常量载入寄存器 eaxmov ebx 2; // 将常量载入寄存器 ebxmov eax 0x1111; // 代码1:假设 a 在内存中的地址是 0x1111;将 eax 的值写入 0x1111 这个内存地址指示的内存中, // 但实际是先写到缓存,然后再在某个时机将缓存值刷到内存中mov ebx 0x2222; // 代码2:同上根据流水线,取址了代码1,就立即取址代码2;然后交给译码->执行->写回;所以代码2有可能会被先执行。这就是重排序。
。。。
java 有3个优先级:MIN_PRIORITY = 1NORM_PRIORITY = 5(默认)MAX_PRIORITY = 10
非阻塞算法
Callable
锁优化
使用
notify()notifyall()
偏向锁
内核层
Thread Scheduler
read
自旋锁、自适应自旋锁
并发容器
Bitfields | Tag | State
完成
7
操作系统的线程实现方式
迭代器与Concurrent-ModificationException
java规定的五种【线程状态】
保证变量对所有线程的【可见性】
一个volatile变量,必须先回写到内存,别的线程才能读
JMM 使用 volatile 和 synchronized 来保证多线程间的有序性
a = 123
基础构建模块
测试
8
关闭
取消
jvm层
使用 【用户线程+轻量级进程】 混合实现
任务执行
Broked
规则:线程安全 - 对象共享
构建自定义同步工具
同步容器类的问题
限期等待:时间一到,即可唤醒
也是通过CAS 将 锁记录替换回去
阻塞:在等待一个互斥锁
开始访问
assign
执行
Synchronized、Lock(CAS)
a` = 123
同步容器
《Java并发编程实战》
局部变量表
sleep()
1
基于优先级
收藏
收藏
0 条评论
下一页