1. synchronized
- synchronized方法的锁,就是该方法所在的对象本身
- 静态synchronized方法从Class对象上获取锁
- 每个Java对象都可以作为同步锁使用
- 内置锁(intrinsic locks)
- 监视器锁(monitor locks)
- 互斥锁(mutual exclusion lock,Mutex)
- 可重入(Reentrancy)
- 持有锁的线程
- 对应的计数器,请求计数器(acquisition count)
- 临界区
- 内存可见性
- 重排序(reordering)
- 过期数据
- JVM 32 slot
- 导致64位变量并发不安全
- 同步
- 线程A执行一个同步块时,线程B随后也进入同一个临界区
- 则A在同步块之中/之前的操作,对B都是可见的
- 线程A执行一个同步块时,线程B随后也进入同一个临界区
2. volatile
- 同步的弱形式
- 确保对一个变量的更新以可预见的方式告知其他的线程
- 共享变量
- 不会重排序
- 不会缓存在寄存器
- 不会缓存在处理器中
- 读取时,总会返回某个线程所写入的最新值
- 轻量级的同步机制
- 不会引发线程阻塞
- 不会加锁
- 通常当作标志使用
- 完成
- 中断
- 状态
- 加锁可以保证
- 可见性
- 原子性
- volatile
- 可见性
- 单写多读
3. 发布/逸出
- 使数据/对象能够被当前范围之外的代码所使用,称为发布
- 一个对象在尚未准备好时就发布出去,称为逸出
- 间接发布
- get方法直接返回引用
- 内部类中this逸出(构造器中的this)
- 构造器中将内部类发布出去
- 使用内部final变量 + 工厂方法来避免
- 对象初始化过程的同步
- 变量的默认初始值
- 相当于两次赋值
- 变量的默认初始值
- 安全发布
- 通过静态初始化器初始化对象的引用
- 将它的引用存储到volatile域或AtomicReference
- 将它的引用存储到正确创建的对象的final域中
- 将它的引用存储到由锁正确保护的域中
4. 线程封闭
- 数据总是在同一个线程中被访问,就不需要任何同步
- 如:Swing中的invokeLater机制
- 在事件线程中安排执行Runnable
- 池化
- 资源在同一时间点,只能分配给一个线程使用
- Ad-hoc 线程限制
- 维护线程限制性的任务都由开发人员来实现
- 易损性
- 未经过设计而得到的线程封闭行为
- 栈限制
- 局部变量都在线程栈中
- 其他线程无法访问
- 引用的对象,还是需要额外的同步机制
- ThreadLocal
- 降低重用性
- 不可滥用
5. 不可变性
- 创建后状态不能被修改的对象,称为:不可变对象
- 线程安全
- 注意this逸出问题
- final 域
- 初始化安全性
6. 同步器(Synchronizer)
- 用来调节相互协作的线程间的控制流
- 同步容器
- 早期JDK
- Vector
- Hashtable
Collections.synchronizedXxx
工厂方法- 使用自身作为锁(
synchronized
)- 并发性弱
- 锁竞争激烈
- 吞吐量低
- Iterator
- 单线程中可在遍历过程中,对内容增减
- 但多线程中,由于可见性等问题,仍然无法避免并发问题
- 多线程场景中,即便使用Iterator,仍然需要考虑同步机制
- fail-fast
- ConcurrentModificationException
- 早期JDK
- 并发容器
- Queue
- ConcurrentLinkedQueue
- FIFO
- PriorityQueue
- 优先级
- 非并发
- ConcurrentLinkedQueue
- BlockingQueue
- 生产者-消费者
- 异步
- 解耦
- 需要考虑:是否有界
- 防止程序过载,耗尽内存
- FIFO队列
- LinkedBlockingQueue
- ArrayBlockingQueue
- 优先级队列
- PriorityBlockingQueue
- ConcurrentHashMap
- 锁策略
- 分段锁
- 链表尾部加锁(Java 8)
- 迭代器弱一致性
- 无法客户端加锁
- 锁策略
- CopyOnWriteArrayList
- 写时复制
- 避免在迭代期间对容器加锁和复制
- 不可变数据的线程安全特性
- 复制带来额外开销
- 数组复制
- 数据量比较大时,性能开销大
- Queue
- 同步器队列
- SynchronousQueue
- 维护一个排队的线程清单
- Blocking
- 没有存储功能
- SynchronousQueue
- Deque
- BlockingDeque
- 窃取工作
- work-stealing
- 同步器
- 阻塞队列(BlockingQueue)
- 闭锁(latch)
- 阻塞一组线程,直到某些事件发生
- CountDownLatch
- FutureTask
- 变相闭锁
- 一旦进入完成状态,会永远停止在这个状态上
- 信号量(semaphore)
- 用来控制同时访问某特定资源的活动的数量
- 管理着一个有效的许可(permit)集
- 二元信号量
- 计数初始值为:1
- 变相的:互斥锁
- 不可重入锁
- 栅栏(barrier)
- 阻塞一组线程,直到所有的线程到达
- 闭锁等待事件,栅栏等待线程
- CyclicBarrier
await
会给每一个线程返回一个唯一的到达索引号- 可用于选举
- Exchanger
- 变相栅栏
- 相位(phaser)
7. 任务(task)
- 抽象、离散的工作单元
- 清晰的任务边界(task boundaries)
- 资源隔离
- 独立性
- 并不依赖于其他任务的状态、结果或者边界效应(side effect)
- 独立有利于并发性
- Runnable
8. Executor 框架
- 管理两种资源
- 任务
- 类型
- Runnable
- Callable
- 任务队列
- BlockQueue
- 类型
- 线程
- 线程工厂
- 线程池
- ThreadPoolExecutor
- ScheduledThreadPoolExecutor
- ForkJoinPool
- 任务
- 将任务与线程解耦
- 提供统一地生命周期/回调
- 执行策略
- 任务在什么(++what++)线程中执行
- 任务以什么(++what++)顺序执行(FIFO,LIFO,优先级)
- 可以有多少个(++how many++)任务并发执行
- 可以有多少个(++how many++)任务进入等待执行队列
- 如果系统过载,需要放弃一个任务,应该挑选哪一个(++which++)任务
- 如何(++how++)通知应用程序知道这一切
- 在一个任务的执行前与结束后,应该做什么(++what++)处理
- 生命周期
- ExecutorService的3种状态
- 运行(running)
- 关闭(shutting down)
List<Runnable> shutdownNow()
boolean isShutdown()
boolean isTerminated()
boolean awaitTermination(long timeout, TimeUnit unit)
- 终止(termination)
- 任务
- 创建
- 提交
- 开始
- 完成
- ExecutorService的3种状态
- 拒绝执行处理器
java.util.concurrent.RejectedExecutionHandler
- 周期性任务
- ScheduledThreadPoolExecutor
- 异步任务处理
java.util.concurrent.ExecutorCompletionService<V>
- 任务队列
- 无限队列
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
- 有限队列
- 同步移交
- 无限队列
- 饱和策略
9. 中断
- 处理可取消
- 用户请求取消
- 限时活动
- 应用程序事件
- 错误
- 关闭
- 没有绝对安全的停止线程的方法
- 相互协作的机制
- 大循环/关键步骤的重要检查点:线程是否中断
- api
public boolean isInterrupted()
public void interrupt()
public static boolean interrupted()
- 中断策略
- 最有意义的是对线程级(thread-level)和服务级(service level)取消的规定
- 尽可能迅速退出
- 如需清理,尽可能通知相关实体
- 此线程已经退出
- 区分任务和线程对中断的反应
- 最有意义的是对线程级(thread-level)和服务级(service level)取消的规定
- 通过Future取消任务
- 通过致命药丸关闭线程
- 无界队列
- 显式Lock提供
lockInterruptibly
在锁等待时,还能响应中断 - 定制
newTaskFor
方法,来封装非标准的取消动作
10. 异常
UncaughtExeceptionHandler