Android 线程同步知多少

3 阅读21分钟

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 = 1;  ← 重排序!                      │
│     其他线程看到 flag=true 但 a 还未赋值                         │
│                                                                │
└────────────────────────────────────────────────────────────────┘
各同步机制解决的问题对应关系:

┌──────────────────────┬─────────┬─────────┬─────────┐
│        机制           │ 原子性   │ 可见性   │ 有序性   │
├──────────────────────┼─────────┼─────────┼─────────┤
│ synchronized         │   ✓     │   ✓     │   ✓     │
│ volatile             │   ✗     │   ✓     │   ✓     │
│ Lock                 │   ✓     │   ✓     │   ✓     │
│ Atomic               │   ✓     │   ✓     │   ✓     │
│ final                │   -     │   ✓     │   ✓     │
│ Handler(串行化)       │   ✓*    │   ✓*    │   ✓*    │
└──────────────────────┴─────────┴─────────┴─────────┘
 * Handler 通过消息串行化避免并发,间接保证三个特性

三、synchronized — 内置锁

基本用法

// ① 同步方法 — 锁是 this 对象
public synchronized void increment() {
    count++;
}

// ② 同步静态方法 — 锁是 Class 对象
public static synchronized void staticMethod() {
    // 锁是 MyClass.class
}

// ③ 同步代码块 — 锁是指定对象 (推荐,粒度更细)
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 而非 if (防止虚假唤醒)
            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() {
    // 耗时操作1 (不需要同步)
    String data = downloadFromNetwork();

    // 需要同步的操作
    cache.put(key, data);

    // 耗时操作2 (不需要同步)
    notifyUI(data);
}

// ✅ 锁粒度最小化
public void processData() {
    String data = downloadFromNetwork();  // 不加锁

    synchronized (cache) {                // 只锁需要同步的部分
        cache.put(key, data);
    }

    notifyUI(data);                       // 不加锁
}

// ❌ 用 String/Integer 等作为锁对象
synchronized ("lock") { }         // String常量池 → 不同类可能锁同一个
synchronized (Integer.valueOf(1)) { } // 缓存 → 意外共享

// ✅ 用 private final Object 作为锁
private final Object lock = new Object();
synchronized (lock) { }

// ❌ 嵌套锁 → 死锁风险
synchronized (lockA) {
    synchronized (lockB) { } // 如果另一个线程先锁B再锁A → 死锁
}

// ✅ 固定加锁顺序
// 始终按 lockA → 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                │
└──────────────────────────────────────────────────────────────┘

典型使用场景

// ✅ 场景1: 状态标志 (一写多读)
private volatile boolean isRunning = true;

// 线程A
public void stop() {
    isRunning = false;  // 写
}

// 线程B
public void run() {
    while (isRunning) {  // 读 → 能立即看到最新值
        doWork();
    }
}

// ✅ 场景2: 双重检查锁 (DCL) 单例
public class Singleton {
    // volatile 防止指令重排序
    private static volatile Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {                // 第一次检查 (无锁)
            synchronized (Singleton.class) {
                if (instance == null) {        // 第二次检查 (有锁)
                    instance = new Singleton();
                    // 没有 volatile, 这里可能重排序:
                    // ① 分配内存 ② 引用赋值 ③ 构造函数
                    // 重排为: ① → ② → ③
                    // 其他线程看到 instance != null 但未初始化完成!
                }
            }
        }
        return instance;
    }
}

// ✅ 场景3: 轻量级发布
private volatile Config config;

// 更新线程
public void updateConfig(Config newConfig) {
    // newConfig 内部状态已构造完成
    config = newConfig;  // volatile 写保证其他线程看到完整的 newConfig
}

// 读取线程
public void useConfig() {
    Config c = config;  // volatile 读
    c.apply();          // 安全使用
}

volatile 不能做什么

// ❌ volatile 不保证原子性!
private volatile int count = 0;

// 线程A和B同时执行:
count++;  // 不是原子操作! 仍然有竞态条件
// 等价于:
// int temp = count;     // 读 (volatile 读)
// temp = temp + 1;      // 改 (普通操作)
// count = temp;         // 写 (volatile 写)
// 两个线程可能读到同一个值!

// ✅ 复合操作用 AtomicInteger
private final AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();  // CAS 原子操作

五、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();  // ⚠️ 必须在 finally 中释放!
    }
}

高级特性

// ① 可中断锁 — 等待锁时可被中断
public void interruptibleTask() throws InterruptedException {
    lock.lockInterruptibly();  // 等待时可被 thread.interrupt() 中断
    try {
        doWork();
    } finally {
        lock.unlock();
    }
}

// ② 超时尝试 — 避免永久等待
public boolean tryTask() {
    boolean acquired = false;
    try {
        acquired = lock.tryLock(3, TimeUnit.SECONDS);  // 最多等3秒
        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);  // true = 公平
// 先等待的线程先获得锁
// 代价: 吞吐量降低 (需要维护等待队列)

Condition — 条件变量

// 比 wait/notify 更灵活: 多个条件队列
class BoundedBuffer<T> {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();   // 条件1: 非满
    private final Condition notEmpty = lock.newCondition();  // 条件2: 非空
    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();  // 在 writeLock 释放前获取 readLock
            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 — 最常用
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();    // ++count (原子)
count.getAndIncrement();    // count++ (原子)
count.addAndGet(5);         // count += 5 (原子)
count.compareAndSet(5, 10); // if(count==5) count=10 (原子)
count.updateAndGet(x -> x * 2); // count *= 2 (原子, Java 8)

// ② AtomicBoolean — 状态标志
AtomicBoolean initialized = new AtomicBoolean(false);
if (initialized.compareAndSet(false, true)) {
    // 保证只有一个线程进入此块
    doInitialization();
}

// ③ AtomicReference — 原子引用
AtomicReference<Config> configRef = new AtomicReference<>(defaultConfig);
configRef.compareAndSet(oldConfig, newConfig);
Config current = configRef.get();

// ④ AtomicIntegerArray — 原子整型数组
AtomicIntegerArray array = new AtomicIntegerArray(10);
array.incrementAndGet(0);  // 原子递增第0个元素

// ⑤ AtomicStampedReference — 解决 ABA 问题
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 — 高并发计数器 (性能优于 AtomicLong)
LongAdder adder = new LongAdder();
adder.increment();  // 分段CAS, 减少竞争
long total = adder.sum();  // 汇总所有段

// 性能对比 (高并发下):
// AtomicLong:  所有线程 CAS 同一个变量 → 竞争激烈
// LongAdder:   每个线程 CAS 自己的 Cell → 最后求和
//              吞吐量高 5-10 倍

自旋锁实现

// 用 AtomicInteger 实现简单的自旋锁
class SpinLock {
    private final AtomicReference<Thread> owner = new AtomicReference<>();

    public void lock() {
        Thread current = Thread.currentThread();
        while (!owner.compareAndSet(null, current)) {
            // 自旋等待
            Thread.yield(); // 让出CPU, 减少空转
        }
    }

    public void unlock() {
        owner.compareAndSet(Thread.currentThread(), null);
    }
}

八、并发工具类

1. CountDownLatch — 等待多个任务完成

// 场景: 主线程等待 N 个子任务完成后继续
// 一次性的,不可重置

CountDownLatch latch = new CountDownLatch(3);  // 计数器 = 3

// 3个并行任务
executor.execute(() -> {
    loadUserInfo();
    latch.countDown();  // 计数器 -1
});
executor.execute(() -> {
    loadOrders();
    latch.countDown();
});
executor.execute(() -> {
    loadRecommends();
    latch.countDown();
});

// 主线程等待
latch.await(5, TimeUnit.SECONDS);  // 阻塞直到计数器=0 或超时
// 所有数据加载完成, 刷新UI
refreshUI();
时间线:
  主线程: ──── await() ───────────────────── 继续执行 ───→
  任务1:  ─── loadUserInfo() ──── countDown()
  任务2:  ─────── loadOrders() ──────── countDown()
  任务3:  ── loadRecommends() ── countDown()
                                          ↑
                                   count=0, 主线程被唤醒

2. CyclicBarrier — 多线程互等

// 场景: N 个线程互相等待,全部到达后同时继续
// 可重用

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 — 信号量(限流)

// 场景: 限制同时访问资源的线程数
// Android: 限制同时下载数、数据库连接数

Semaphore semaphore = new Semaphore(3);  // 最多3个线程同时执行

for (int i = 0; i < 10; i++) {
    executor.execute(() -> {
        try {
            semaphore.acquire();  // 获取许可 (计数器-1, 为0时阻塞)
            Log.d("Task", "执行下载, 当前并发: " + (3 - semaphore.availablePermits()));
            downloadFile();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            semaphore.release();  // 释放许可 (计数器+1)
        }
    });
}

// tryAcquire: 非阻塞尝试
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<>();

// 线程A
executor.execute(() -> {
    String dataA = "来自A的数据";
    String fromB = exchanger.exchange(dataA);  // 阻塞等待B
    Log.d("A", "收到B的数据: " + fromB);
});

// 线程B
executor.execute(() -> {
    String dataB = "来自B的数据";
    String fromA = exchanger.exchange(dataB);  // 阻塞等待A
    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 详解

// ❌ 错误: HashMap 多线程下不安全
Map<String, Integer> map = new HashMap<>();
// 多线程同时 put → 可能死循环(JDK7) / 数据丢失(JDK8)

// ❌ 错误: Hashtable 全表锁,性能差
Map<String, Integer> map = new Hashtable<>();
// 所有操作都 synchronized(this) → 严重竞争

// ❌ 错误: Collections.synchronizedMap 包装,同样全表锁
Map<String, Integer> map = Collections.synchronizedMap(new HashMap<>());

// ✅ 正确: ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1);
map.get("key");

// ⚠️ 复合操作仍需注意!
// ❌ 非原子复合操作 (check-then-act)
if (!map.containsKey("key")) {  // 检查
    map.put("key", 1);          // 操作 → 两步之间可能被其他线程插入!
}

// ✅ 原子复合操作
map.putIfAbsent("key", 1);     // 原子操作
map.computeIfAbsent("key", k -> expensiveCompute(k));  // 原子操作
map.merge("key", 1, Integer::sum);  // 原子 merge
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<>();

// 写操作: 复制整个数组,修改副本,替换引用
// 代价: 每次写都复制 → 内存+GC压力
listeners.add(listener);     // 内部: Arrays.copyOf + 新数组

// 读操作: 无锁,直接读当前数组引用
for (EventListener l : listeners) {  // 无锁迭代
    l.onEvent(event);                // 迭代期间的写操作不影响当前迭代
}

// ⚠️ 不适合写频繁的场景!
// 每次 add/remove 都复制整个数组
写时复制原理:

初始状态:
  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 实现线程安全

// 核心思想: 把对共享资源的操作全部 post 到同一个 Handler
// 由 Looper 串行执行 → 不需要任何锁!

class SafeCounter {
    private final Handler handler;
    private int count = 0;  // 只在 handler 线程中访问,无需 volatile

    SafeCounter() {
        HandlerThread ht = new HandlerThread("counter-thread");
        ht.start();
        handler = new Handler(ht.getLooper());
    }

    // 任意线程调用
    public void increment() {
        handler.post(() -> {
            count++;  // 在 handler 线程串行执行,线程安全
        });
    }

    // 任意线程调用
    public void getCount(Consumer<Integer> callback) {
        handler.post(() -> {
            callback.accept(count);  // 在 handler 线程读取
        });
    }
}

HandlerThread — Android 推荐的工作线程

// 自带 Looper 的工作线程
HandlerThread handlerThread = new HandlerThread("db-writer",
    Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();

Handler dbHandler = new Handler(handlerThread.getLooper());

// 所有数据库写操作 post 到同一个 Handler → 串行化
dbHandler.post(() -> database.insert(record1));
dbHandler.post(() -> database.insert(record2));
dbHandler.post(() -> database.update(record3));
// 保证执行顺序: insert1 → insert2 → update3

// 释放
handlerThread.quitSafely();
Handler 串行化 vs 传统锁:

┌────────────────────┬──────────────────────────────┐
│    传统锁方式        │       Handler 串行化方式       │
├────────────────────┼──────────────────────────────┤
│ synchronized(lock) │ handler.post()               │
│ 线程阻塞等待锁      │ 立即返回, 异步执行             │
│ 可能死锁            │ 不会死锁                      │
│ 需要处处加锁        │ 只需 post 到正确的 Handler     │
│ 同步执行,有返回值   │ 异步执行,通过回调获取结果       │
│ 适合简短临界区      │ 适合串行的异步操作              │
└────────────────────┴──────────────────────────────┘

十一、Kotlin Coroutines 同步

Mutex — 协程互斥锁

// ⚠️ 协程中不能用 synchronized/ReentrantLock
// 因为挂起时不会释放锁 → 可能阻塞整个线程池

val mutex = Mutex()
var count = 0

suspend fun safeIncrement() {
    mutex.withLock {  // 挂起等待,不阻塞线程
        count++
    }
}

// 1000 个协程并发
coroutineScope {
    repeat(1000) {
        launch {
            safeIncrement()
        }
    }
}
println(count)  // 正确输出 1000
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++
    }
}

// 更实用的方式: Dispatchers.Main
// UI 操作全部在主线程 → 不需要同步
lifecycleScope.launch {
    val data = withContext(Dispatchers.IO) { fetchData() }
    // 回到主线程, 访问 UI 不需要同步
    textView.text = data
    adapter.submitList(data.items)
}

Channel — 协程间通信

// Channel = 协程版的 BlockingQueue
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")
    }
}

// Channel 容量策略:
// Channel.RENDEZVOUS (0)  — 无缓冲, 发送方等待接收方
// Channel.BUFFERED (64)   — 默认缓冲
// Channel.UNLIMITED       — 无限缓冲
// Channel.CONFLATED       — 只保留最新值

Flow — 冷流(响应式数据流)

// StateFlow — 替代 LiveData 的线程安全状态
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)
            }
        }
    }
}

// Activity 中收集
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)
            }
        }
    }
}

协程中的原子操作

// AtomicInteger 仍然可用
val count = AtomicInteger(0)

coroutineScope {
    repeat(1000) {
        launch(Dispatchers.Default) {
            count.incrementAndGet()
        }
    }
}
println(count.get())  // 1000

// Kotlin 的 atomic 库 (kotlinx-atomicfu)
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();

// 线程1: 先锁A再锁B
thread1: synchronized (lockA) {
             sleep(100);
             synchronized (lockB) {  // 等待线程2释放B
                 doWork();
             }
         }

// 线程2: 先锁B再锁A
thread2: synchronized (lockB) {
             sleep(100);
             synchronized (lockA) {  // 等待线程1释放A → 死锁!
                 doWork();
             }
         }
死锁检测:

方式1: ANR 日志 (traces.txt)
  adb pull /data/anr/traces.txt
  → 查看线程状态: BLOCKED / WAITING
  → 查看持有的锁和等待的锁

方式2: Android Studio Debugger
  → Thread Dump
  → 查看死锁线程

方式3: 代码检测
  Thread.getAllStackTraces() → 分析线程状态
// ✅ 解决方案1: 固定加锁顺序 (破坏循环等待)
// 始终按 lockA → lockB 的顺序
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();
    }
}

// ✅ 解决方案2: 使用 tryLock + 超时 (破坏不可剥夺)
if (lockA.tryLock(1, TimeUnit.SECONDS)) {
    try {
        if (lockB.tryLock(1, TimeUnit.SECONDS)) {
            try {
                doWork();
            } finally {
                lockB.unlock();
            }
        }
    } finally {
        lockA.unlock();
    }
}

// ✅ 解决方案3: 一次性获取所有锁 (破坏持有并等待)
// ✅ 解决方案4: 用 Handler 串行化, 根本不需要多把锁

十三、Android 常见同步场景与最佳方案

场景 1:单例模式

// 方案1: DCL (Double-Checked Locking)
public class Singleton {
    private static volatile Singleton instance;  // volatile!

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

// 方案2: 静态内部类 (推荐, 线程安全 + 懒加载)
public class Singleton {
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
        // 类加载机制保证线程安全
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

// 方案3: Kotlin object (底层就是方案2)
object Singleton {
    fun doSomething() { }
}

// 方案4: 枚举单例 (最安全, 防序列化/反射攻击)
public enum Singleton {
    INSTANCE;
    public void doSomething() { }
}

场景 2:缓存读写

// ✅ 推荐: ConcurrentHashMap + 原子操作
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);
    }
}

// ✅ 如果需要 LRU 淘汰: LruCache (内部已 synchronized)
LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(maxSize) {
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }
};
// LruCache 内部所有方法都是 synchronized, 线程安全

场景 3:事件总线 / 监听器列表

// ✅ CopyOnWriteArrayList (读多写少)
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 状态更新

// ✅ 最佳方案: StateFlow + viewModelScope
class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState

    fun updateName(name: String) {
        viewModelScope.launch {
            // StateFlow.update 是线程安全的原子操作
            _uiState.update { it.copy(name = name) }
        }
    }
}

// ✅ 次选: LiveData (setValue 只能主线程, postValue 任意线程)
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:计数器 / 统计

// ✅ AtomicInteger / AtomicLong
private final AtomicInteger requestCount = new AtomicInteger(0);
private final AtomicLong totalBytes = new AtomicLong(0);

void onRequestComplete(long bytes) {
    requestCount.incrementAndGet();
    totalBytes.addAndGet(bytes);
}

// ✅ 高并发计数: LongAdder (性能更优)
private final LongAdder eventCount = new LongAdder();
void onEvent() {
    eventCount.increment();
}
long total = eventCount.sum();

场景 6:延迟初始化

// ✅ Kotlin lazy (默认线程安全)
val heavyObject: ExpensiveObject by lazy {
    ExpensiveObject()  // 只执行一次, 线程安全 (DCL)
}

// 指定模式
val obj1 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }   // 线程安全(默认)
val obj2 by lazy(LazyThreadSafetyMode.PUBLICATION) { ... }     // 允许多次初始化,但只用第一个
val obj3 by lazy(LazyThreadSafetyMode.NONE) { ... }            // 不安全(单线程用)

场景 7:数据库操作

// ✅ Room 自动管理线程安全
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    suspend fun getAll(): List<User>  // 自动在后台线程执行

    @Insert
    suspend fun insert(user: User)    // Room 内部保证事务线程安全
}

// ✅ 手动管理: HandlerThread 串行化
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