TreeMap 和 TreeSet 线程安全
TreeMap
和 TreeSet
不是线程安全的集合,因此必须注意确保在多线程程序中使用时。
TreeMap
和 TreeSet
在多线程读取时都是安全的,甚至是同时读取的。因此,如果它们是由单个线程创建并填充的(例如,在程序的开头),然后只读,但不被多个线程修改,则没有理由进行同步或锁定。
但是,如果同时读取和修改,或者由多个线程同时修改,则集合可能会抛出 ConcurrentModificationException 或意外行为。在这些情况下,必须使用以下方法之一同步/锁定对集合的访问:
-
使用
Collections.synchronizedSorted..
:SortedSet<Integer> set = Collections.synchronizedSortedSet(new TreeSet<Integer>()); SortedMap<Integer,String> map = Collections.synchronizedSortedMap(new TreeMap<Integer,String>());
这将提供由实际集合支持的 SortedSet / SortedMap 实现,并在某些互斥对象上进行同步。请注意,这将在单个锁上同步对集合的所有读写访问权限,因此即使是并发读取也是不可能的。
-
通过手动同步某个对象,如集合本身:
TreeSet<Integer> set = new TreeSet<>();
…
//Thread 1 synchronized (set) { set.add(4); }
…
//Thread 2 synchronized (set) { set.remove(5); }
-
通过使用锁,例如 ReentrantReadWriteLock :
TreeSet<Integer> set = new TreeSet<>(); ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
…
//Thread 1 lock.writeLock().lock(); set.add(4); lock.writeLock().unlock();
…
//Thread 2 lock.readLock().lock(); set.contains(5); lock.readLock().unlock();
与之前的同步方法相反,使用 ReadWriteLock 允许多个线程同时从映射中读取。