Kotlin中如何为LinkedHashSet加锁避免并发修改异常?
解决方案
1. 给所有集合操作加同一把锁
你之前只在序列化时加了锁,但如果其他线程修改集合(添加、删除元素)时没同步加锁,照样会触发并发修改异常。所有读写LinkedHashSet的地方,都要用synchronized(linkedHashSet)包裹:
// 添加元素示例 synchronized(linkedHashSet) { linkedHashSet.add(newElement) } // 删除元素示例 synchronized(linkedHashSet) { linkedHashSet.remove(oldElement) }
确保所有操作都在同一锁的保护下,从根源避免并发冲突。
2. 序列化前先复制集合快照
如果担心序列化耗时太长、锁持有时间过久,可以在锁内先复制一份集合的快照,再对快照做序列化:
CoroutineScope(Dispatchers.IO).launch { val snapshot: LinkedHashSet<*> synchronized(linkedHashSet) { snapshot = LinkedHashSet(linkedHashSet) // 复制出完全独立的快照 } // 对快照序列化,此时原集合可以正常被其他线程修改 val jsonString = Gson().toJson(snapshot) sharedPreferences?.edit()?.putString("DataList", jsonString)?.apply() }
这种方式缩短了锁的持有时间,只在复制快照时加锁,序列化操作在锁外执行,能提升并发性能。
3. 改用线程安全的包装集合
初始化集合时用Collections.synchronizedSet()包装LinkedHashSet,得到一个内置锁保护的线程安全集合:
// 初始化时就包装 val safeLinkedHashSet = Collections.synchronizedSet(LinkedHashSet<YourDataType>())
之后读写操作直接调用safeLinkedHashSet的方法即可,但注意遍历/序列化时仍需手动加锁(因为集合的迭代器本身不是线程安全的):
CoroutineScope(Dispatchers.IO).launch { synchronized(safeLinkedHashSet) { val jsonString = Gson().toJson(safeLinkedHashSet) sharedPreferences?.edit()?.putString("DataList", jsonString)?.apply() } }
4. 用读写锁优化读多写少场景
如果你的业务里读操作(序列化、查询)远多于写操作(增删元素),可以用ReentrantReadWriteLock替代synchronized,读锁允许多线程同时访问,写锁互斥,能提升并发效率:
// 全局定义读写锁 val rwLock = ReentrantReadWriteLock() // 写操作(添加/删除元素)示例 rwLock.writeLock().lock() try { linkedHashSet.add(newElement) } finally { rwLock.writeLock().unlock() } // 序列化(读操作) CoroutineScope(Dispatchers.IO).launch { rwLock.readLock().lock() try { val jsonString = Gson().toJson(linkedHashSet) sharedPreferences?.edit()?.putString("DataList", jsonString)?.apply() } finally { rwLock.readLock().unlock() } }
内容的提问来源于stack exchange,提问作者s k
相关产品推荐
相关产品推荐

