线程非安全的集合类包含了ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap,实际开发中我们自己使用最多的一般是这样的集合,因为一般情况下我们自己写的业务代码中涉及到多线程共享同一个集合的问题。我们都是在一个函数方法内使用到了容器集合,而这种局部的容器使用方式,是线程之间隔离的,不会存在线程安全问题。
线程安全的集合类包含了Vector、HashTable虽然没有JUC中的高性能集合高,但是也能够适应大部分的环境。
高性能线程安全的集合类包含了,ConcurrentHashMap、CopyOnWriteArrayList。
在 Java 中,解决集合类的高并发问题通常涉及到线程安全性和并发控制。Java 提供了多种线程安全的集合类以及工具类来帮助开发者构建高性能的并发应用程序。下面是一些常用的线程安全集合类和工具:
线程安全的集合类
- Vector:
- 继承自 AbstractList,实现了 List 接口。
- 所有的公共方法都是同步的,适用于单个线程写入和多个线程读取的场景。
- 由于方法同步,可能会导致写操作阻塞读操作,不适合高并发场景。
- Hashtable:
- 实现了 Map 接口。
- 同样是同步的,所有的公共方法都是线程安全的。
- 不允许键或值为 null。
- 性能较低,因为整个哈希表在写操作时会被锁定。
- ConcurrentHashMap:
- 实现了 Map 接口。
- 使用分段锁来实现线程安全,提高了并发性能。
- 允许键和值为 null。
- 提供了 putIfAbsent(), remove() 和 replace() 等原子操作,非常适合并发场景。
- CopyOnWriteArrayList 和 CopyOnWriteArraySet:
- 分别实现了 List 和 Set 接口。
- 在修改列表或集合时创建新副本,保留旧副本供读取操作使用。
- 适用于读多写少的场景,因为写操作需要复制整个列表或集合,性能较差。
- LinkedBlockingQueue, ArrayBlockingQueue, PriorityBlockingQueue:
- 实现了 Queue 接口。
- 提供了阻塞操作,如 take() 和 put(),允许线程在队列为空或满时等待。
- 适用于生产者-消费者模式。
- ConcurrentLinkedQueue:
- 实现了 Queue 接口。
- 使用无锁算法,通过 CAS (Compare and Swap) 操作实现线程安全。
- 适用于高并发的队列操作。
并发工具类
- Collections.synchronizedList(), synchronizedSet(), ****synchronizedMap():
- 提供静态工厂方法来包装非线程安全的集合类,使其成为线程安全的。
- 通常在集合对象创建后立即调用这些方法。
- 适用于不需要高度并发的场景。
- Collections.unmodifiableList(), unmodifiableSet(), ****unmodifiableMap():
- 创建不可变的视图,使集合只读。
- 适用于读多写少的场景,可以避免修改操作带来的线程安全问题。
- ReentrantLock:
- 提供了一个显式锁,可以替代 synchronized 关键字。
- 支持公平和非公平锁,以及条件变量等高级功能。
- ReadWriteLock:
- 提供读写锁,允许多个读取线程同时访问资源,但写操作是独占的。
- 适用于读多写少的场景,可以显著提高并发性能。
- Semaphore 和 CountDownLatch:
- 提供了信号量和倒计时锁存器,用于控制对共享资源的访问次数或协调线程间的同步。
实际应用
在实际项目中,选择合适的线程安全集合类取决于具体的使用场景和性能要求: - 如果需要高度并发的读写操作,可以选择 ConcurrentHashMap。
- 对于需要阻塞操作的队列,可以使用 LinkedBlockingQueue 或 ArrayBlockingQueue。
- 如果读操作远多于写操作,可以考虑使用 CopyOnWriteArrayList 或 ConcurrentHashMap。
- 如果需要对集合进行加锁操作,可以使用 ReentrantLock 或 ReadWriteLock。