当多个线程访问某个类时, 不管运行时环境采用何种调度方式或者这些线程将如何交替执行, 并且在主调代码中不需要任何额外的同步或协同, 这个类都能表现出正确的行为, 那么就称这个类是线程安全的
当某个计算的正确性取决于多个线程的交替执行时, 那么就会发生竞态条件. 换句话说, 就是正确的结果要取决于运气. 最常见的竞态条件就是"先检查后执行(Check-Then-Act)"操作, 即通过一个可能失效的观测结果来决定下一步的动作.
假定有两个操作A 和B, 如果从执行A 的线程来看, 当另一个线程执行B 时, 要么将B 全部执行完, 要么完全不执行B, 那么A 和B 对彼此来说就是原子的. 原子操作是指, 对于访问同一个状态的所有操作(包括该操作本身)来说, 这个操作是一个以原子方式执行的操作.
对于可能被多个线程同时访问的可变状态变量, 在访问它时都需要持有同一个锁, 在这种情况下, 我们称状态变量是由这个锁保护的.
- 当且仅当满足以下所有条件时, 才应当使用volatile 变量(java 运算符对应多条jvm 指令)
- 对变量的写入操作不依赖变量的当前值, 或者你能确保只有单个线程更新变量的值
- 该变量不会与其他状态变量一并纳入不变性条件
- 在访问变量时不需要加锁
当某个对象封闭在一个线程中是, 这种用法将自动实现线程安全性, 即使被封闭的对象本身不是线程安全的.
- ThreadLocal
- 动态数据源
- MDC
- 不安全发布
- 安全发布的常用模式
- 在静态初始化函数中初始化一个对象引用
- 将对象引用保存到volatile 类型的域或者AtomicReference 对象中
- 将对象引用保存到某个正确构造对象的final 类型域中
- 将对象引用保存到一个由锁保护的域中
- ConcurrentHashMap
- CopyOnWriteArrayList
- 在每次修改时, 都会创建并重新发布一个新的容器副本
- 仅当迭代操作远远多于修改操作时, 才应该使用
- CopyOnWriteArraySet
- LinkedBlockingQueue
- ArrayBlockingQueue
- 静态工厂方法
- newFixedThreadPool
- newCachedThreadPool
- newSingleTHreadExecutor
- newScheduledThreadPool
- 生命周期
- 设置线程池大小
- 工作队列 ArrayBlockingQueue & LinkedBlockingQueue & SynchronousQueue
- submit 源码分析
- 饱和策略
- 自定义线程工厂
"条件队列"这个名字来源于: 它使得一组线程(称之为等待线程集合)能够通过某种方式来等待特定的条件变成真
-
条件谓词
条件谓词是使某个操作成为状态依赖的前提条件. 在有界缓存中, 只有当缓存不为空时, take 方法才能执行, 否则必须等待. 对take 方法来说, 它的条件条件谓词就是"缓存不为空"
-
过早唤醒
-
通知
每当在等待一个条件时, 一定要确保在条件谓词变为真时, 通过某种方式发出通知
- 若多个条件谓词等待同一条件队列, 则使用nofifyAll 而非notify, 否则容易产生信号丢失问题
- 为何要使用
- BoundedBuffer, 两个条件谓词均使用同一条件队列, 使用notifyAll, 造成性能损耗
- 便于分析, 不同条件谓词对应不同条件队列, 对应不同signal 入口
- 与内置条件队列区别
- ArrayBlockingQueue 源码
- LinkedBlockingQueue 源码
- 为何使用
- 处理大量细节, 等待线程采用FIFO 队列操作顺序
- lock, condition 两时刻阻塞; AQS 一时刻阻塞
- AbstractQueuedSynchronizer
- CountDownLatch
- Java 并发编程实战
- Java™ Platform, Standard Edition 8 API Specification









































































































