Java内存模型
- 主内存
- 变量都存储在主内存
- 类比硬件主内存
- 线程间变量值的传递需要主内存来完成
- 工作内存
- 每条线程都有自己的工作内存,保存该线程用到的变量的主内存副本拷贝
- 类比硬件高速缓存
- 线程对变量的操作都必须在工作内存中进行,不能直接读写主内存的变量
- 内存间交互原子操作
- lock: 主内存变量 -> 线程独占
- unlock: 主内存变量 -> 释放状态
- read: 主内存变量 -> 传输到工作内存
- load: 主内存变量 -> 放入工作内存副本
- use: 工作内存变量 -> 执行引擎
- assign: 工作内存变量 -> 赋值
- store: 工作内存变量 -> 传输到主内存
- write: 主内存变量 -> 写入
等效于[先行发生]原则
- 保证三个特征
- 原子性
- 读写具备原子性
- synchronized具备原子性
- 可见性
- 通过变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量保证
- volatile变量保证新值立即同步主内存,普通变量则不能保证"立即"
- volatile、final、synchronized
- 有序性
- 线程内部是串行的,但存在指令重排序和工作内存与主内存同步延迟的现象
- volatile关键字本身包含了禁止指令重排序的语义
- synchronized保证一个变量同一时刻只有一个线程对其进行Lock
- 原子性
- 先行发生
时间上先发生的操作并不就是先行发生,发生后产生的影响能被另一个操作观察到,才称作先行发生- 一个线程内按照代码顺序,写在前面的操作先行发生于后面的操作
- unlock先行发生于后面的lock
- volatile的写操作先行发生于后面的读操作
- Thread的start()先行发生于后续操作,线程中的所有操作先行发生于线程的终止检测
- 线程的interrupt()先行发生于被中断线程检测到中断事件的发生
- 对象的初始化先行发生于它的finalize()
- 具有传递性
Java线程
- win&linux使用内核线程实现
- 直接由操作系统内核支持
- 轻量级进程(即线程)与内核线程1:1
- 系统调用需要在内核态和用户态切换
- 数量有限
- 抢占式调度
- 5种状态
- 新建
- 运行
- [无限期|限期]等待
- 等待一段时间,或唤醒动作的发生
- 阻塞
- 等待另一个线程放弃锁
- 结束
线程安全
- 互斥同步
- synchronized : 语法级
- ReetrantLock : API级
- 等待可中断
- 公平锁
- 锁可绑定多个条件
- 非阻塞同步
- 乐观 CAS
- 无同步方案
- 可重入代码
- 线程本地存储
锁优化
-
自旋锁
- 阻塞时,挂起和恢复线程开销很大
- 尝试看看持有锁的线程是否很快释放,为了让线程等待,执行一个忙循环
- 自适应: 自选时间不再固定,而是根据经验
-
锁消除
- 逃逸分析,检测到不可能存在数据竞争的锁进行消除
-
锁粗化
- 一系列操作都是对同一个对象反复加锁解锁
- 锁同步范围扩展到整个操作序列外部
-
轻量级锁
- 对象头中(Mark Word)存储锁状态信息
- 假定锁无竞争,使用CAS操作同步
- 如果有2个以上线程竞争锁,膨胀为重量级锁
-
偏向锁
- 跟轻量级锁的实现一样,通过设置对象头中的锁状态信息实现
- 假定锁无竞争,把同步操作消除掉
- 锁会偏向于第一个获得它的线程,如果后续该锁没有被其他线程获取,持有偏向锁的线程不需要同步
- 如果有另外一个线程尝试获取锁,偏向模式结束,转为未锁定或轻量级锁