1. 引言

上一篇文章中,我们探索了Guava 21中common.collect包的新增功能。本文将快速梳理common.util.concurrent包的重要更新,这些改进在高并发场景中特别实用。

2. AtomicLongMap

在并发环境中,标准HashMap的表现往往不尽如人意,因为它不是线程安全的。这时AtomicLongMap就能派上用场,它能以线程安全的方式存储Long值。

⚠️ 踩坑提醒:直接在并发场景使用HashMap可能导致数据错乱,改用AtomicLongMap是更稳妥的选择。

Guava 11就引入了AtomicLongMap,而在21版本中新增了四个实用方法:

2.1. accumulateAndGet()

该方法通过累加函数更新键值,并返回更新后的值:

@Test
public void accumulateAndGet_withLongBinaryOperator_thenSuccessful() {
    long noOfStudents = 56;
    long oldValue = courses.get(SPRING_COURSE_KEY);

    long totalNotesRequired = courses.accumulateAndGet(
      "Guava", 
      noOfStudents, 
      (x, y) -> (x * y));

    assertEquals(totalNotesRequired, oldValue * noOfStudents);
}

2.2. getAndAccumulate()

功能与accumulateAndGet()类似,但返回的是更新前的值(方法名已经暗示了操作顺序)。

2.3. updateAndGet()

使用指定函数更新键值,并返回更新后的值:

@Test
public void updateAndGet_withLongUnaryOperator_thenSuccessful() {
    long beforeUpdate = courses.get(SPRING_COURSE_KEY);
    long onUpdate = courses.updateAndGet(
      "Guava",
      (x) -> (x / 2));
    long afterUpdate = courses.get(SPRING_COURSE_KEY);

    assertEquals(onUpdate, afterUpdate);
    assertEquals(afterUpdate, beforeUpdate / 2);
}

2.4. getAndUpdate()

updateAndGet()功能相同,但返回的是更新前的值

3. Monitor

Monitor类被视为ReentrantLock的替代方案,代码更易读且不易出错。

3.1. Monitor.newGuard()

Guava 21新增的newGuard()方法返回Monitor.Guard实例,作为线程等待的布尔条件:

public class MonitorExample {
    private List<String> students = new ArrayList<String>();
    private static final int MAX_SIZE = 100;

    private Monitor monitor = new Monitor();

    public void addToCourse(String item) throws InterruptedException {
        Monitor.Guard studentsBelowCapacity = monitor.newGuard(this::isStudentsCapacityUptoLimit);
        monitor.enterWhen(studentsBelowCapacity);
        try {
            students.add(item);
        } finally {
            monitor.leave();
        }
    }

    public Boolean isStudentsCapacityUptoLimit() {
        return students.size() > MAX_SIZE;
    }
}

✅ 实践技巧:使用Monitor替代显式锁能减少死锁风险,条件判断逻辑也更清晰。

4. MoreExecutors

这个类没有新增功能,但移除了sameThreadExecutor()方法(自v18.0起已废弃)。推荐改用:

  • directExecutor()
  • newDirectExecutorService()

5. ForwardingBlockingDeque

ForwardingBlockingDequecommon.collect包迁移至此,因为BlockingQueue本质上属于并发集合而非普通集合。

6. 总结

Guava 21不仅紧跟Java 8步伐引入新工具,还持续优化现有模型使其更具实用价值。本文所有示例代码可在GitHub仓库中获取。

🔍 关键收获:

  • AtomicLongMap新增方法简化了并发计数操作
  • Monitor提供更安全的锁机制
  • 及时淘汰废弃API保持库的整洁性

原始标题:Guide to common.util.concurrent in Guava 21