TreeMap 和 TreeSet 线程安全

TreeMapTreeSet 不是线程安全的集合,因此必须注意确保在多线程程序中使用时。

TreeMapTreeSet 在多线程读取时都是安全的,甚至是同时读取的。因此,如果它们是由单个线程创建并填充的(例如,在程序的开头),然后只读,但不被多个线程修改,则没有理由进行同步或锁定。

但是,如果同时读取和修改,或者由多个线程同时修改,则集合可能会抛出 ConcurrentModificationException 或意外行为。在这些情况下,必须使用以下方法之一同步/锁定对集合的访问:

  1. 使用 Collections.synchronizedSorted..

    SortedSet<Integer> set = Collections.synchronizedSortedSet(new TreeSet<Integer>());
    SortedMap<Integer,String> map = Collections.synchronizedSortedMap(new TreeMap<Integer,String>());
    

    这将提供由实际集合支持的 SortedSet / SortedMap 实现,并在某些互斥对象上进行同步。请注意,这将在单个锁上同步对集合的所有读写访问权限,因此即使是并发读取也是不可能的。

  2. 通过手动同步某个对象,如集合本身:

     TreeSet<Integer> set = new TreeSet<>(); 
    

    //Thread 1
    synchronized (set) {
        set.add(4);
    }
    

    //Thread 2
    synchronized (set) {
        set.remove(5);
    }        
    
  3. 通过使用锁,例如 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 允许多个线程同时从映射中读取。