// 线程安全的 List
List<String> list = Collections.synchronizedList(new ArrayList<>());
synchronized (list) {
for (String item : list) {
// 遍历时仍需要手动同步
}
}// 线程安全的 Map
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1);
Integer value = map.get("key");// CopyOnWriteArrayList — 写时复制,读多写少适用
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("item");// BlockingQueue — 生产者-消费者模式
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.put("task"); // 队列满时阻塞
String task = queue.take(); // 队列空时阻塞
Collections.synchronizedList 只保护单个方法调用,遍历时仍需要手动 synchronized 块,容易漏加导致并发异常。ConcurrentHashMap 粒度细但 API 复杂。BlockingQueue 阻塞的是线程,在协程中直接阻塞线程会浪费线程资源。

// 单线程访问 — 协程天然单线程处理
// ViewModel 中,所有对同一数据的操作都通过 viewModelScope
private val _items = MutableStateFlow<List<String>>(emptyList())fun addItem(item: String) {
_items.update { current ->
current + item // 内部线程安全,不需要显式锁
}
}// 生产者-消费者 — Channel 替代 BlockingQueue
private val channel = Channel<String>(capacity = Channel.BUFFERED)viewModelScope.launch {
// 生产者
channel.send("task") // 挂起,不阻塞线程
}viewModelScope.launch {
// 消费者
for (task in channel) {
processTask(task)
}
}// 并发限制 — Semaphore
private val semaphore = Semaphore(3)viewModelScope.launch {
semaphore.withPermit {
doLimitedWork()
}
}// 读写场景 — Mutex
private val mutex = Mutex()suspend fun updateSafely(block: () -> Unit) {
mutex.withLock {
block()
}
}
MutableStateFlow.update {} 内部是原子操作,读-改-写三个步骤不会被其他协程打断,不需要额外加锁。但 StateFlow.value = list + item 这种两步操作就不是原子的了,两个协程同时读再写会丢数据,应始终用 update {}。
Channel.send() 是挂起函数,消费者没在监听时生产者会被挂起等待,不消耗线程。这是 Channel 比 BlockingQueue 更适合协程的关键区别——BlockingQueue 会真的阻塞线程,Channel 只是挂起协程。
Mutex.withLock 也是挂起的,不像 Java synchronized 会阻塞线程,所以 Main 线程用 Mutex 也安全。
Java Android 老项目迁移系列,持续更新中。