# Java中并发容器J.U.C怎么用 ## 一、J.U.C概述 Java并发工具包(Java Util Concurrent,简称J.U.C)是Java 5引入的一组高质量并发编程工具,位于`java.util.concurrent`包下。它提供了比传统同步容器更高效的线程安全实现,主要包含以下组件: 1. **并发集合**:替代同步集合的高性能线程安全容器 2. **同步器**:如CountDownLatch、CyclicBarrier等 3. **线程池**:Executor框架 4. **原子变量**:AtomicInteger等 5. **锁机制**:ReentrantLock等 ## 二、核心并发容器详解 ### 1. ConcurrentHashMap #### 基本用法 ```java ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("key1", 1); map.putIfAbsent("key1", 2); // 不存在才放入 int value = map.get("key1"); // 原子更新 map.compute("key1", (k, v) -> v == null ? 1 : v + 1); // 搜索 String result = map.search(1, (k, v) -> v > 100 ? k : null); // 批量操作 map.forEach(2, (k, v) -> System.out.println(k + ":" + v)); 读多写少的并发场景,如事件监听器列表
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("item1"); // 写时复制 String item = list.get(0); // 无锁读取 无界非阻塞队列实现:
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>(); queue.offer("element1"); String head = queue.poll(); 特点: - CAS实现的无锁算法 - 高性能但size()方法需要遍历
有界阻塞队列:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10); queue.put("item"); // 阻塞插入 String item = queue.take(); // 阻塞取出 可选有界/无界:
// 无界队列 BlockingQueue<String> unbounded = new LinkedBlockingQueue<>(); // 有界队列 BlockingQueue<String> bounded = new LinkedBlockingQueue<>(100); 带优先级的无界队列:
BlockingQueue<Task> queue = new PriorityBlockingQueue<>(11, Comparator.comparing(Task::getPriority)); 延迟队列:
class DelayItem implements Delayed { // 必须实现getDelay()和compareTo() } DelayQueue<DelayItem> delayQueue = new DelayQueue<>(); 跳表实现的并发有序Map:
ConcurrentSkipListMap<Integer, String> map = new ConcurrentSkipListMap<>(); map.put(3, "three"); map.put(1, "one"); // 保证遍历顺序是1->3 | 容器 | 特点 | 适用场景 |
|---|---|---|
| ConcurrentHashMap | 高并发K-V存储 | 缓存、共享数据存储 |
| CopyOnWriteArrayList | 读多写少 | 监听器列表、配置数据 |
| ConcurrentLinkedQueue | 无界非阻塞队列 | 任务队列、消息传递 |
| ArrayBlockingQueue | 有界阻塞队列 | 生产者-消费者模式 |
| LinkedBlockingQueue | 可选有界队列 | 线程池工作队列 |
| ConcurrentSkipListMap | 有序并发Map | 需要排序的并发数据 |
合理选择容器类型:
避免热点竞争:
// 不好的做法 - 所有修改竞争同一键 map.compute("counter", (k, v) -> v + 1); // 更好的做法 - 分散热点 map.compute(Thread.currentThread().getName(), (k, v) -> v + 1); // 使用批量操作方法 ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.putAll(otherMap); // 而不是循环put for(Map.Entry<String, Integer> entry : otherMap.entrySet()) { map.put(entry.getKey(), entry.getValue()); // 多次获取锁 } 问题代码:
if(!map.containsKey(key)) { map.put(key, value); // 非原子操作 } 解决方案:
map.putIfAbsent(key, value); // 或者使用compute map.compute(key, (k, v) -> v == null ? value : v); 迭代时可能不反映最新修改:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // ...添加元素... // 迭代期间可能有修改 for(String key : map.keySet()) { // 可能看到部分修改 } 解决方案:
// 如果需要强一致性,需要额外同步 synchronized(map) { for(String key : map.keySet()) { // ... } } 确保修改对其他线程可见:
// 不安全的发布 class UnsafeHolder { public static ConcurrentHashMap unsafeMap; } // 正确做法 class SafeHolder { private static final ConcurrentHashMap safeMap = new ConcurrentHashMap(); public static ConcurrentHashMap getMap() { return safeMap; } } Java 8引入的并行操作方法:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // 并行forEach map.forEach(2, (k, v) -> System.out.println(k + ":" + v)); // 并行reduce int sum = map.reduceValues(2, Integer::sum); // 并行search String key = map.search(2, (k, v) -> v > 100 ? k : null); 实现生产者-消费者模式:
class CustomBlockingQueue<T> { private final Queue<T> queue = new LinkedList<>(); private final int limit; public CustomBlockingQueue(int limit) { this.limit = limit; } public synchronized void put(T item) throws InterruptedException { while(queue.size() == limit) { wait(); } queue.add(item); notifyAll(); } public synchronized T take() throws InterruptedException { while(queue.isEmpty()) { wait(); } T item = queue.remove(); notifyAll(); return item; } } public class InventorySystem { private final ConcurrentHashMap<String, AtomicInteger> inventory; public InventorySystem() { inventory = new ConcurrentHashMap<>(); } // 线程安全的库存扣减 public boolean deduct(String productId, int quantity) { return inventory.computeIfPresent(productId, (k, v) -> { int remaining = v.get() - quantity; return remaining >= 0 ? new AtomicInteger(remaining) : v; }) != null; } // 批量查询 public Map<String, Integer> getInventoryStatus(Set<String> productIds) { return productIds.stream() .collect(Collectors.toMap( id -> id, id -> inventory.getOrDefault(id, new AtomicInteger(0)).get() )); } } 通过合理使用J.U.C并发容器,可以构建出高性能、线程安全的并发系统。开发者应当根据具体场景选择合适的容器,并充分理解其特性才能发挥最大效益。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。