Android 线程同步
一、全景架构
┌─────────────────────────────────────────────────────────────────────┐
│ Android 线程同步机制全景 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Java 层同步原语 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │
│ │ │ synchronized │ │ volatile │ │ final 不可变 │ │ │
│ │ │ (内置锁) │ │ (可见性保证) │ │ (安全发布) │ │ │
│ │ └──────────────┘ └──────────────┘ └────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ JUC (java.util.concurrent) │ │
│ │ ┌────────────┐ ┌────────────┐ ┌─────────────────────────┐ │ │
│ │ │ Lock 体系 │ │ Atomic 原子 │ │ 并发工具 │ │ │
│ │ │ ReentrantLock│ │ AtomicInt │ │ CountDownLatch │ │ │
│ │ │ ReadWriteLock│ │ AtomicRef │ │ CyclicBarrier │ │ │
│ │ │ Condition │ │ AtomicBool │ │ Semaphore │ │ │
│ │ │ StampedLock │ │ LongAdder │ │ Exchanger │ │ │
│ │ └────────────┘ └────────────┘ └─────────────────────────┘ │ │
│ │ ┌───────────────────────────────────────────────────────┐ │ │
│ │ │ 并发容器 │ │ │
│ │ │ ConcurrentHashMap │ CopyOnWriteArrayList │ │ │
│ │ │ BlockingQueue │ ConcurrentLinkedQueue │ │ │
│ │ └───────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Android 特有机制 │ │
│ │ ┌────────────────────┐ ┌────────────────────────────┐ │ │
│ │ │ Handler/Looper │ │ HandlerThread │ │ │
│ │ │ (消息驱动的串行化) │ │ (自带 Looper 的工作线程) │ │ │
│ │ └────────────────────┘ └────────────────────────────┘ │ │
│ │ ┌────────────────────┐ ┌────────────────────────────┐ │ │
│ │ │ AsyncTask (已废弃) │ │ IntentService (已废弃) │ │ │
│ │ └────────────────────┘ └────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 现代方案 │ │
│ │ ┌────────────────────┐ ┌────────────────────────────┐ │ │
│ │ │ Kotlin Coroutines │ │ Flow / Channel / Mutex │ │ │
│ │ │ (结构化并发) │ │ (协程同步原语) │ │ │
│ │ └────────────────────┘ └────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
二、线程安全三大核心问题
┌────────────────────────────────────────────────────────────────┐
│ │
│ 1. 原子性 (Atomicity) │
│ "操作不可分割,要么全部完成,要么全部不做" │
│ 问题: count++ 不是原子操作 (读→改→写 三步) │
│ 线程A: 读count=0 → 加1 → 写count=1 │
│ 线程B: 读count=0 → 加1 → 写count=1 ← 丢失了一次更新! │
│ │
│ 2. 可见性 (Visibility) │
│ "一个线程的修改,其他线程能立即看到" │
│ 问题: CPU 缓存 / 编译器优化 导致线程间不可见 │
│ 线程A: flag = true (写入 CPU 缓存,未刷回主存) │
│ 线程B: while(!flag) (从自己的 CPU 缓存读,永远是 false) │
│ │
│ 3. 有序性 (Ordering) │
│ "程序执行顺序与代码顺序一致" │
│ 问题: 编译器/CPU 指令重排序 │
│ 代码: a = 1
│ 实际: flag = true
│ 其他线程看到 flag=true 但 a 还未赋值 │
│ │
└────────────────────────────────────────────────────────────────┘
各同步机制解决的问题对应关系:
┌──────────────────────┬─────────┬─────────┬─────────┐
│ 机制 │ 原子性 │ 可见性 │ 有序性 │
├──────────────────────┼─────────┼─────────┼─────────┤
│ synchronized │ ✓ │ ✓ │ ✓ │
│ volatile │ ✗ │ ✓ │ ✓ │
│ Lock │ ✓ │ ✓ │ ✓ │
│ Atomic │ ✓ │ ✓ │ ✓ │
│ final │ - │ ✓ │ ✓ │
│ Handler(串行化) │ ✓* │ ✓* │ ✓* │
└──────────────────────┴─────────┴─────────┴─────────┘
* Handler 通过消息串行化避免并发,间接保证三个特性
三、synchronized — 内置锁
基本用法
public synchronized void increment() {
count++;
}
public static synchronized void staticMethod() {
}
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
底层原理
┌──────────────────────────────────────────────────────────────┐
│ synchronized 底层实现 │
│ │
│ Java 对象头 (Object Header): │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Mark Word (32/64 bit) │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ 锁状态标志 │ 线程ID │ 偏向时间戳 │ HashCode │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Klass Pointer (指向类元数据) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ 锁升级过程 (JVM 优化, 不可降级): │
│ │
│ 无锁 → 偏向锁 → 轻量级锁 → 重量级锁 │
│ │
│ 偏向锁: │
│ 只有一个线程访问 → Mark Word 记录线程ID │
│ 再次进入 → 检查ID一致 → 直接进入 (无CAS) │
│ → 适合单线程反复获取同一把锁 │
│ │
│ 轻量级锁 (自旋锁): │
│ 有竞争但不激烈 → CAS 竞争锁 │
│ 获取失败 → 自旋等待 (循环尝试,不阻塞线程) │
│ → 适合锁持有时间短的场景 │
│ │
│ 重量级锁 (互斥锁): │
│ 竞争激烈 → 升级为 Monitor (操作系统 Mutex) │
│ 获取失败 → 线程阻塞 (进入内核态,上下文切换) │
│ → 竞争激烈时不可避免 │
│ │
│ 字节码层面: │
│ 同步块: monitorenter / monitorexit │
│ 同步方法: ACC_SYNCHRONIZED 方法标志 │
└──────────────────────────────────────────────────────────────┘
wait / notify — 条件等待
class BoundedBuffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int capacity = 10;
private final Object lock = new Object();
public void produce(int value) throws InterruptedException {
synchronized (lock) {
while (queue.size() == capacity) {
lock.wait();
}
queue.add(value);
lock.notifyAll();
}
}
public int consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait();
}
int value = queue.poll();
lock.notifyAll();
return value;
}
}
}
wait/notify 流程:
线程A (生产者): 线程B (消费者):
synchronized(lock) synchronized(lock)
│ │
├── queue满 → lock.wait() ├── queue空 → lock.wait()
│ ├── 释放 lock │ ├── 释放 lock
│ ├── 进入 WaitSet │ ├── 进入 WaitSet
│ └── 阻塞... │ └── 阻塞...
│ │
│ ←── 被notify唤醒 │ ←── 被notify唤醒
│ ├── 重新竞争 lock │ ├── 重新竞争 lock
│ ├── 获取成功 │ ├── 获取成功
│ └── 从wait()返回 │ └── 从wait()返回
│ while检查条件 │ while检查条件
│ │
synchronized 最佳实践
public synchronized void processData() {
String data = downloadFromNetwork();
cache.put(key, data);
notifyUI(data);
}
public void processData() {
String data = downloadFromNetwork();
synchronized (cache) {
cache.put(key, data);
}
notifyUI(data);
}
synchronized ("lock") { }
synchronized (Integer.valueOf(1)) { }
private final Object lock = new Object();
synchronized (lock) { }
synchronized (lockA) {
synchronized (lockB) { }
}
四、volatile — 可见性与有序性
原理
┌──────────────────────────────────────────────────────────────┐
│ volatile 内存语义 │
│ │
│ CPU 0 CPU 1 │
│ ┌──────────┐ ┌──────────┐ │
│ │ L1 Cache │ │ L1 Cache │ │
│ │ flag=false│ │ flag=false│ ← 各自缓存副本 │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └────────┬────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Main Memory │ │
│ │ flag = false │ │
│ └─────────────────┘ │
│ │
│ 写 volatile: │
│ 线程A: flag = true │
│ → ① 写入 L1 Cache │
│ → ② 立即刷回主存 (store barrier) │
│ → ③ 使其他 CPU 的缓存行失效 (MESI 协议) │
│ │
│ 读 volatile: │
│ 线程B: if (flag) │
│ → ① 缓存行已失效 │
│ → ② 从主存重新加载 (load barrier) │
│ → ③ 读到最新值 true │
│ │
│ 内存屏障 (Memory Barrier): │
│ volatile 写前: StoreStore barrier (禁止写写重排) │
│ volatile 写后: StoreLoad barrier (禁止写读重排) │
│ volatile 读后: LoadLoad + LoadStore barrier │
└──────────────────────────────────────────────────────────────┘
典型使用场景
private volatile boolean isRunning = true;
public void stop() {
isRunning = false;
}
public void run() {
while (isRunning) {
doWork();
}
}
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
private volatile Config config;
public void updateConfig(Config newConfig) {
config = newConfig;
}
public void useConfig() {
Config c = config;
c.apply();
}
volatile 不能做什么
private volatile int count = 0;
count++;
private final AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
五、ReentrantLock — 显式锁
synchronized vs ReentrantLock
┌──────────────────┬─────────────────────┬──────────────────────┐
│ 特性 │ synchronized │ ReentrantLock │
├──────────────────┼─────────────────────┼──────────────────────┤
│ 锁获取/释放 │ 自动 (进入/退出) │ 手动 lock()/unlock() │
│ 可中断 │ ✗ │ ✓ lockInterruptibly()│
│ 超时尝试 │ ✗ │ ✓ tryLock(timeout) │
│ 公平锁 │ ✗ (非公平) │ ✓ new(true) │
│ 多条件变量 │ ✗ (只有一个wait set) │ ✓ newCondition() │
│ 锁状态查询 │ ✗ │ ✓ isLocked()等 │
│ 性能 │ JVM持续优化,接近 │ 早期更优,现在接近 │
│ 死锁风险 │ 忘不了释放 │ ⚠️ 忘记unlock→死锁 │
│ 推荐 │ 简单场景首选 │ 需要高级特性时使用 │
└──────────────────┴─────────────────────┴──────────────────────┘
基本用法
private final ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
sharedResource.modify();
} finally {
lock.unlock();
}
}
高级特性
public void interruptibleTask() throws InterruptedException {
lock.lockInterruptibly();
try {
doWork();
} finally {
lock.unlock();
}
}
public boolean tryTask() {
boolean acquired = false;
try {
acquired = lock.tryLock(3, TimeUnit.SECONDS);
if (acquired) {
doWork();
return true;
} else {
Log.w("Lock", "获取锁超时,执行降级逻辑");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
} finally {
if (acquired) lock.unlock();
}
}
public void nonBlockingTask() {
if (lock.tryLock()) {
try {
doWork();
} finally {
lock.unlock();
}
} else {
doAlternative();
}
}
ReentrantLock fairLock = new ReentrantLock(true);
Condition — 条件变量
class BoundedBuffer<T> {
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Queue<T> queue = new LinkedList<>();
private final int capacity;
public BoundedBuffer(int capacity) { this.capacity = capacity; }
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await();
}
queue.add(item);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await();
}
T item = queue.poll();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
synchronized wait/notify:
┌────────────────────────┐
│ 一个等待队列 (WaitSet) │
│ 生产者和消费者混在一起 │
│ notifyAll → 全部唤醒 │ ← 可能唤醒不该唤醒的线程
└────────────────────────┘
Condition:
┌──────────────┐ ┌──────────────┐
│ notFull 队列 │ │ notEmpty 队列 │
│ 生产者等待 │ │ 消费者等待 │
└──────────────┘ └──────────────┘
signal → 精确唤醒对应队列中的线程
六、ReadWriteLock — 读写锁
┌──────────────────────────────────────────────────────────┐
│ ReadWriteLock 规则 │
│ │
│ ┌────────────┬─────────────────┬──────────────────────┐ │
│ │ │ 持有读锁的线程 │ 持有写锁的线程 │ │
│ ├────────────┼─────────────────┼──────────────────────┤ │
│ │ 请求读锁 │ ✓ 允许(共享) │ ✗ 阻塞(互斥) │ │
│ │ 请求写锁 │ ✗ 阻塞(互斥) │ ✗ 阻塞(互斥) │ │
│ └────────────┴─────────────────┴──────────────────────┘ │
│ │
│ 读-读: 共享 (不阻塞) │
│ 读-写: 互斥 (阻塞) │
│ 写-写: 互斥 (阻塞) │
│ │
│ 适用场景: 读多写少 (缓存 / 配置 / 共享数据) │
└──────────────────────────────────────────────────────────┘
class ThreadSafeCache<K, V> {
private final Map<K, V> map = new HashMap<>();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
public V get(K key) {
readLock.lock();
try {
return map.get(key);
} finally {
readLock.unlock();
}
}
public void put(K key, V value) {
writeLock.lock();
try {
map.put(key, value);
} finally {
writeLock.unlock();
}
}
public V computeIfAbsent(K key, Function<K, V> compute) {
readLock.lock();
try {
V value = map.get(key);
if (value != null) return value;
} finally {
readLock.unlock();
}
writeLock.lock();
try {
V value = map.get(key);
if (value != null) return value;
value = compute.apply(key);
map.put(key, value);
readLock.lock();
return value;
} finally {
writeLock.unlock();
readLock.unlock();
}
}
}
性能对比 (读多写少场景):
synchronized: 读 ─────────────────── 写 ─── 读 ─── 读 ─── 写
串行 串行 串行 串行 串行
ReadWriteLock: 读 ─┐ 写 ─── 读 ─┐
读 ─┤ 并发 串行 读 ─┤ 并发
读 ─┘ 读 ─┘
吞吐量提升 2-10 倍 (取决于读写比例)
七、Atomic — 原子类 (CAS)
CAS 原理
┌──────────────────────────────────────────────────────────┐
│ CAS (Compare And Swap) 原理 │
│ │
│ 操作: compareAndSet(expected, newValue) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ CPU 指令级原子操作 (x86: CMPXCHG + LOCK前缀) │ │
│ │ │ │
│ │ if (当前值 == expected) { │ │
│ │ 当前值 = newValue; │ │
│ │ return true;
│ │ } else { │ │
│ │ return false;
│ │ } │ │
│ │ │ │
│ │ 整个过程是 CPU 硬件级别保证的原子操作! │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ 优点: 无锁 (Lock-Free), 无上下文切换 │
│ 缺点: ① 自旋消耗CPU ② ABA问题 ③ 只能保护单个变量 │
└──────────────────────────────────────────────────────────┘
常用原子类
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
count.getAndIncrement();
count.addAndGet(5);
count.compareAndSet(5, 10);
count.updateAndGet(x -> x * 2);
AtomicBoolean initialized = new AtomicBoolean(false);
if (initialized.compareAndSet(false, true)) {
doInitialization();
}
AtomicReference<Config> configRef = new AtomicReference<>(defaultConfig);
configRef.compareAndSet(oldConfig, newConfig);
Config current = configRef.get();
AtomicIntegerArray array = new AtomicIntegerArray(10);
array.incrementAndGet(0);
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
int[] stampHolder = new int[1];
String current = ref.get(stampHolder);
ref.compareAndSet("A", "B", stampHolder[0], stampHolder[0] + 1);
LongAdder adder = new LongAdder();
adder.increment();
long total = adder.sum();
自旋锁实现
class SpinLock {
private final AtomicReference<Thread> owner = new AtomicReference<>();
public void lock() {
Thread current = Thread.currentThread();
while (!owner.compareAndSet(null, current)) {
Thread.yield();
}
}
public void unlock() {
owner.compareAndSet(Thread.currentThread(), null);
}
}
八、并发工具类
1. CountDownLatch — 等待多个任务完成
CountDownLatch latch = new CountDownLatch(3);
executor.execute(() -> {
loadUserInfo();
latch.countDown();
});
executor.execute(() -> {
loadOrders();
latch.countDown();
});
executor.execute(() -> {
loadRecommends();
latch.countDown();
});
latch.await(5, TimeUnit.SECONDS);
refreshUI();
时间线:
主线程: ──── await() ───────────────────── 继续执行 ───→
任务1: ─── loadUserInfo() ──── countDown()
任务2: ─────── loadOrders() ──────── countDown()
任务3: ── loadRecommends() ── countDown()
↑
count=0, 主线程被唤醒
2. CyclicBarrier — 多线程互等
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
Log.d("Barrier", "所有线程到达屏障点!");
});
for (int i = 0; i < 3; i++) {
final int id = i;
executor.execute(() -> {
try {
Log.d("Thread-" + id, "阶段1完成");
barrier.await();
Log.d("Thread-" + id, "阶段2完成");
barrier.await();
Log.d("Thread-" + id, "阶段3完成");
} catch (Exception e) {
e.printStackTrace();
}
});
}
CountDownLatch vs CyclicBarrier:
┌────────────────┬────────────────────┬────────────────────┐
│ │ CountDownLatch │ CyclicBarrier │
├────────────────┼────────────────────┼────────────────────┤
│ 等待方式 │ 一组线程等另一组 │ 线程之间互相等待 │
│ 可重用 │ ✗ 一次性 │ ✓ 可重用 │
│ 计数方向 │ 递减到0 │ 递增到N │
│ 回调 │ ✗ │ ✓ 到达后执行回调 │
│ 异常处理 │ 独立 │ 一个失败全部失败 │
└────────────────┴────────────────────┴────────────────────┘
3. Semaphore — 信号量(限流)
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
try {
semaphore.acquire();
Log.d("Task", "执行下载, 当前并发: " + (3 - semaphore.availablePermits()));
downloadFile();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release();
}
});
}
if (semaphore.tryAcquire(1, TimeUnit.SECONDS)) {
try {
doWork();
} finally {
semaphore.release();
}
} else {
showRateLimitError();
}
Semaphore(3) 运行时:
时刻1: [T1执行] [T2执行] [T3执行] T4等待 T5等待 T6等待
permits=0
时刻2: [T1完成] [T2执行] [T3执行] [T4执行] T5等待 T6等待
T1 release → permits=1 → T4 acquire → permits=0
时刻3: [T2完成] [T5执行] [T3执行] [T4执行] T6等待
T2 release → T5 acquire
4. Exchanger — 线程间数据交换
Exchanger<String> exchanger = new Exchanger<>();
executor.execute(() -> {
String dataA = "来自A的数据";
String fromB = exchanger.exchange(dataA);
Log.d("A", "收到B的数据: " + fromB);
});
executor.execute(() -> {
String dataB = "来自B的数据";
String fromA = exchanger.exchange(dataB);
Log.d("B", "收到A的数据: " + fromA);
});
九、并发容器
┌─────────────────────────────────────────────────────────────────┐
│ 并发容器对比 │
├─────────────────┬───────────────────┬───────────────────────────┤
│ 容器 │ 机制 │ 适用场景 │
├─────────────────┼───────────────────┼───────────────────────────┤
│ ConcurrentHashMap│ 分段锁/CAS(JDK8) │ 高并发读写的Map │
│ │ 不允许null key/val │ 替代 synchronized HashMap │
├─────────────────┼───────────────────┼───────────────────────────┤
│ CopyOnWriteList │ 写时复制整个数组 │ 读极多写极少 │
│ │ 读无锁,写加锁 │ 监听器列表/配置列表 │
├─────────────────┼───────────────────┼───────────────────────────┤
│ ConcurrentLinked │ CAS 无锁链表 │ 高并发队列 │
│ Queue │ │ 生产者-消费者 (非阻塞) │
├─────────────────┼───────────────────┼───────────────────────────┤
│ BlockingQueue │ 锁 + Condition │ 线程池工作队列 │
│ (多种实现) │ put阻塞/take阻塞 │ 生产者-消费者 (阻塞) │
├─────────────────┼───────────────────┼───────────────────────────┤
│ ConcurrentSkip │ 跳表 + CAS │ 高并发有序Map │
│ ListMap │ │ 替代 synchronized TreeMap │
└─────────────────┴───────────────────┴───────────────────────────┘
ConcurrentHashMap 详解
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> map = new Hashtable<>();
Map<String, Integer> map = Collections.synchronizedMap(new HashMap<>());
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1);
map.get("key");
if (!map.containsKey("key")) {
map.put("key", 1);
}
map.putIfAbsent("key", 1);
map.computeIfAbsent("key", k -> expensiveCompute(k));
map.merge("key", 1, Integer::sum);
JDK 8 ConcurrentHashMap 结构:
┌──────────────────────────────────────────┐
│ Node[] table │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ 0 │ │ 1 │ │ 2 │ │ 3 │ │ 4 │ │...│ │
│ └─┬─┘ └─┬─┘ └───┘ └─┬─┘ └───┘ └───┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [K,V] [K,V] [K,V] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [K,V] null [K,V] │
│ │ │ │
│ ▼ 红黑树(>8个) │
│ null │
│ │
│ 读: 无锁 (volatile Node) │
│ 写: 锁住单个桶头节点 (synchronized) │
│ 扩容: 多线程协助扩容 │
└──────────────────────────────────────────┘
CopyOnWriteArrayList 详解
CopyOnWriteArrayList<EventListener> listeners = new CopyOnWriteArrayList<>();
listeners.add(listener);
for (EventListener l : listeners) {
l.onEvent(event);
}
写时复制原理:
初始状态:
array引用 → [A, B, C]
线程1写入D:
array引用 → [A, B, C] ← 线程2仍在读这个
复制 → newArray = [A, B, C, D]
array引用 → [A, B, C, D] ← 原子替换引用
旧数组 [A, B, C] → GC 回收
线程2的迭代: 看到的是旧数组 [A, B, C] (快照)
→ 不会抛出 ConcurrentModificationException
→ 但不会看到最新的 D (弱一致性)
十、Android Handler 机制 — 串行化同步
┌────────────────────────────────────────────────────────────┐
│ Handler / Looper / MessageQueue │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Thread (工作线程) │ │
│ │ │ │
│ │ handler.post(runnable) │ │
│ │ handler.sendMessage(msg) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ MessageQueue │ │ │
│ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │
│ │ │ │ Msg │→│ Msg │→│ Msg │→│ Msg │→│ Msg │ │ │ │
│ │ │ │when1│ │when2│ │when3│ │when4│ │when5│ │ │ │
│ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │ │
│ │ │ (按 when 时间排序的单链表) │ │ │
│ │ └──────────────────────┬──────────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────────────▼──────────────────────┐ │ │
│ │ │ Looper │ │ │
│ │ │ for (;;) { │ │ │
│ │ │ Message msg = queue.next();
│ │ │ msg.target.dispatchMessage(msg); │ │ │
│ │ │ msg.recycle();
│ │ │ } │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Looper 单线程顺序处理 → 天然串行化 → 无需额外同步! │ │
│ └────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
用 Handler 实现线程安全
class SafeCounter {
private final Handler handler;
private int count = 0;
SafeCounter() {
HandlerThread ht = new HandlerThread("counter-thread");
ht.start();
handler = new Handler(ht.getLooper());
}
public void increment() {
handler.post(() -> {
count++;
});
}
public void getCount(Consumer<Integer> callback) {
handler.post(() -> {
callback.accept(count);
});
}
}
HandlerThread — Android 推荐的工作线程
HandlerThread handlerThread = new HandlerThread("db-writer",
Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
Handler dbHandler = new Handler(handlerThread.getLooper());
dbHandler.post(() -> database.insert(record1));
dbHandler.post(() -> database.insert(record2));
dbHandler.post(() -> database.update(record3));
handlerThread.quitSafely();
Handler 串行化 vs 传统锁:
┌────────────────────┬──────────────────────────────┐
│ 传统锁方式 │ Handler 串行化方式 │
├────────────────────┼──────────────────────────────┤
│ synchronized(lock) │ handler.post() │
│ 线程阻塞等待锁 │ 立即返回, 异步执行 │
│ 可能死锁 │ 不会死锁 │
│ 需要处处加锁 │ 只需 post 到正确的 Handler │
│ 同步执行,有返回值 │ 异步执行,通过回调获取结果 │
│ 适合简短临界区 │ 适合串行的异步操作 │
└────────────────────┴──────────────────────────────┘
十一、Kotlin Coroutines 同步
Mutex — 协程互斥锁
val mutex = Mutex()
var count = 0
suspend fun safeIncrement() {
mutex.withLock {
count++
}
}
coroutineScope {
repeat(1000) {
launch {
safeIncrement()
}
}
}
println(count)
synchronized vs Mutex:
synchronized:
Thread-1: 获取锁 → 执行 → suspend!
→ 线程被阻塞,锁未释放
→ 其他使用同一线程池的协程也被阻塞!
Mutex:
Coroutine-1: 获取锁 → 执行 → suspend
→ 协程挂起,线程被释放去执行其他协程
→ 锁仍由 Coroutine-1 持有 (逻辑上)
→ Coroutine-1 恢复后继续持有锁
线程限制 — 最简单的同步方式
val singleThread = newSingleThreadContext("counter")
var count = 0
suspend fun safeIncrement() {
withContext(singleThread) {
count++
}
}
lifecycleScope.launch {
val data = withContext(Dispatchers.IO) { fetchData() }
textView.text = data
adapter.submitList(data.items)
}
Channel — 协程间通信
val channel = Channel<Int>(capacity = Channel.BUFFERED)
launch {
for (i in 1..5) {
channel.send(i)
Log.d("Producer", "发送: $i")
}
channel.close()
}
launch {
for (value in channel) {
Log.d("Consumer", "接收: $value")
}
}
Flow — 冷流(响应式数据流)
class MyViewModel : ViewModel() {
private val _state = MutableStateFlow<UiState>(UiState.Loading)
val state: StateFlow<UiState> = _state.asStateFlow()
fun loadData() {
viewModelScope.launch {
_state.value = UiState.Loading
try {
val data = withContext(Dispatchers.IO) { repository.fetch() }
_state.value = UiState.Success(data)
} catch (e: Exception) {
_state.value = UiState.Error(e)
}
}
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { state ->
when (state) {
is UiState.Loading -> showLoading()
is UiState.Success -> showData(state.data)
is UiState.Error -> showError(state.error)
}
}
}
}
协程中的原子操作
val count = AtomicInteger(0)
coroutineScope {
repeat(1000) {
launch(Dispatchers.Default) {
count.incrementAndGet()
}
}
}
println(count.get())
val counter = atomic(0)
counter.incrementAndGet()
counter.compareAndSet(expect = 5, update = 10)
十二、死锁分析与预防
死锁四个必要条件
┌──────────────────────────────────────────────────────────────┐
│ 死锁四个必要条件 │
│ │
│ 1. 互斥: 资源不能共享,只能一个线程持有 │
│ 2. 持有并等待: 持有一个资源的同时等待另一个 │
│ 3. 不可剥夺: 已获取的资源不能被强制释放 │
│ 4. 循环等待: 线程之间形成环形等待链 │
│ │
│ 破坏任一条件 → 预防死锁 │
└──────────────────────────────────────────────────────────────┘
死锁示例与解决
final Object lockA = new Object();
final Object lockB = new Object();
thread1: synchronized (lockA) {
sleep(100);
synchronized (lockB) {
doWork();
}
}
thread2: synchronized (lockB) {
sleep(100);
synchronized (lockA) {
doWork();
}
}
死锁检测:
方式1: ANR 日志 (traces.txt)
adb pull /data/anr/traces.txt
→ 查看线程状态: BLOCKED / WAITING
→ 查看持有的锁和等待的锁
方式2: Android Studio Debugger
→ Thread Dump
→ 查看死锁线程
方式3: 代码检测
Thread.getAllStackTraces() → 分析线程状态
int hashA = System.identityHashCode(lockA);
int hashB = System.identityHashCode(lockB);
Object first = hashA < hashB ? lockA : lockB;
Object second = hashA < hashB ? lockB : lockA;
synchronized (first) {
synchronized (second) {
doWork();
}
}
if (lockA.tryLock(1, TimeUnit.SECONDS)) {
try {
if (lockB.tryLock(1, TimeUnit.SECONDS)) {
try {
doWork();
} finally {
lockB.unlock();
}
}
} finally {
lockA.unlock();
}
}
十三、Android 常见同步场景与最佳方案
场景 1:单例模式
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
public class Singleton {
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
object Singleton {
fun doSomething() { }
}
public enum Singleton {
INSTANCE;
public void doSomething() { }
}
场景 2:缓存读写
class MemoryCache<K, V> {
private final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>();
private final int maxSize;
public V get(K key) {
return map.get(key);
}
public V getOrCompute(K key, Function<K, V> loader) {
return map.computeIfAbsent(key, loader);
}
public void put(K key, V value) {
map.put(key, value);
}
}
LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
场景 3:事件总线 / 监听器列表
class EventBus {
private final CopyOnWriteArrayList<EventListener> listeners
= new CopyOnWriteArrayList<>();
public void register(EventListener listener) {
listeners.add(listener);
}
public void unregister(EventListener listener) {
listeners.remove(listener);
}
public void post(Event event) {
for (EventListener l : listeners) {
l.onEvent(event);
}
}
}
场景 4:UI 状态更新
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState
fun updateName(name: String) {
viewModelScope.launch {
_uiState.update { it.copy(name = name) }
}
}
}
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun loadData() {
viewModelScope.launch(Dispatchers.IO) {
val result = repository.fetch()
_data.postValue(result)
}
}
}
场景 5:计数器 / 统计
private final AtomicInteger requestCount = new AtomicInteger(0);
private final AtomicLong totalBytes = new AtomicLong(0);
void onRequestComplete(long bytes) {
requestCount.incrementAndGet();
totalBytes.addAndGet(bytes);
}
private final LongAdder eventCount = new LongAdder();
void onEvent() {
eventCount.increment();
}
long total = eventCount.sum();
场景 6:延迟初始化
val heavyObject: ExpensiveObject by lazy {
ExpensiveObject()
}
val obj1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }
val obj2 by lazy(LazyThreadSafetyMode.PUBLICATION) { ... }
val obj3 by lazy(LazyThreadSafetyMode.NONE) { ... }
场景 7:数据库操作
@Dao
interface UserDao {
@Query("SELECT * FROM users")
suspend fun getAll(): List<User>
@Insert
suspend fun insert(user: User)
}
val dbThread = HandlerThread("database")
dbThread.start()
val dbHandler = Handler(dbThread.looper)
dbHandler.post { db.insert(record) }
十四、同步方案选择决策树
需要线程同步?
│
▼
是否可以避免共享状态?
├── 是 → 线程限制 / 消息传递 / 不可变对象
│ ├── Handler 串行化 (Android 推荐)
│ ├── Dispatchers.Main (协程)
│ ├── data class (Kotlin 不可变)
│ └── ThreadLocal (线程隔离)
│
└── 否 → 必须共享状态
│
▼
操作是否简单? (单变量读写/计数器)
├── 是 → Atomic 类 (AtomicInteger/AtomicRef)
│ 或 volatile (仅状态标志,一写多读)
│
└── 否 → 复合操作
│
▼
读写比例如何?
├── 读多写少 → ReadWriteLock
│ CopyOnWriteArrayList
│ ConcurrentHashMap
│
├── 读写均衡 → synchronized (简单场景)
│ ReentrantLock (需高级特性)
│ Mutex (协程中)
│
└── 需要协调 → CountDownLatch (等待完成)
Semaphore (限流)
CyclicBarrier (阶段同步)
Channel (协程通信)
十五、性能对比
┌─────────────────────────────────────────────────────────────────┐
│ 各同步机制性能对比 (从快到慢) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. volatile 读/写 ← 纳秒级, 仅内存屏障 │
│ 2. Atomic CAS (无竞争) ← 纳秒级, 单条 CPU 指令 │
│ 3. synchronized (无竞争/偏向锁) ← 纳秒级, JVM 优化 │
│ 4. Atomic CAS (有竞争) ← 微秒级, 自旋重试 │
│ 5. synchronized (轻量级锁/自旋) ← 微秒级 │
│ 6. ReentrantLock (无竞争) ← 微秒级 │
│ 7. synchronized (重量级锁) ← 微秒~毫秒, 内核态切换 │
│ 8. ReentrantLock (有竞争) ← 微秒~毫秒 │
│ 9. 线程上下文切换 ← 微秒级 (~10μs) │
│ │
│ Android 特别注意: │
│ - 主线程任何阻塞都可能造成卡顿 (16.6ms 帧预算) │
│ - 尽量用无锁方案 (Atomic / volatile / Handler 串行化) │
│ - 锁持有时间越短越好 │
│ - 协程 Mutex 不阻塞线程,优于 synchronized │
└─────────────────────────────────────────────────────────────────┘
十六、完整对比总表
┌──────────────────┬────────────┬────────┬─────────┬──────────────────┐
│ 机制 │ 阻塞/挂起 │ 可重入 │ 公平性 │ 最佳场景 │
├──────────────────┼────────────┼────────┼─────────┼──────────────────┤
│ synchronized │ 阻塞 │ ✓ │ 非公平 │ 简单互斥 │
│ ReentrantLock │ 阻塞 │ ✓ │ 可选 │ 需超时/中断/公平 │
│ ReadWriteLock │ 阻塞 │ ✓ │ 可选 │ 读多写少 │
│ volatile │ 无 │ - │ - │ 状态标志 │
│ AtomicXxx │ 自旋(不阻塞)│ - │ - │ 计数器/CAS操作 │
│ ConcurrentHashMap│ 分段锁 │ - │ - │ 并发Map │
│ CopyOnWriteList │ 写时复制 │ - │ - │ 读多写少的List │
│ CountDownLatch │ 阻塞 │ - │ - │ 等待N个任务完成 │
│ Semaphore │ 阻塞 │ - │ 可选 │ 限流/资源池 │
│ Handler │ 异步 │ - │ FIFO │ Android线程通信 │
│ Mutex(协程) │ 挂起(不阻塞)│ ✗ │ 公平 │ 协程中的互斥 │
│ Channel(协程) │ 挂起 │ - │ FIFO │ 协程间通信 │
│ StateFlow │ 无 │ - │ - │ UI状态管理 │
└──────────────────┴────────────┴────────┴─────────┴──────────────────┘
总结
Android 线程同步核心原则:
1. 能避免共享就避免
→ 不可变对象 / 线程限制 / 消息传递
→ "最好的锁是不需要锁"
2. 能用高级工具就不用低级原语
→ Kotlin Coroutines > Handler > Lock > synchronized
→ StateFlow/Channel > wait/notify
3. 锁粒度最小化
→ 只锁必要的代码
→ 锁持有时间越短越好
4. 主线程绝不阻塞
→ 不要在主线程使用 synchronized 等待锁
→ 用 Handler.post / Coroutines / 回调
5. 选择正确的工具
→ 简单标志: volatile
→ 计数器: AtomicInteger / LongAdder
→ 并发Map: ConcurrentHashMap
→ 串行任务: Handler / SingleThread
→ 协程: Mutex / Channel / StateFlow