Java集合上的原子拷贝和清除

时间:2015-04-08 13:59:36

标签: java multithreading collections concurrency

我知道经常会问类似的问题,但我找不到任何可以帮助我的事情。

情况是这样的:

  • 一名工人正在向集合中添加元素
  • 第二个是等待一段时间(元素的成熟)或一定的收集规模,并开始工作。

问题是:如何复制(我认为最好是复制)第二个工人的集合,然后清除原始集合以确保我们不会丢失任何东西(第一个工人一直在写)但是不要尽可能地锁定原始收藏品?

感谢

3 个答案:

答案 0 :(得分:8)

如果您使用专用的并发工具(如LinkedBlockingQueue而不是普通的HashSet),这种事情会容易得多。让生产者向队列添加元素,并且消费者可以使用drainTo按需要批量提取队列中的元素。不需要任何同步,因为BlockingQueue实现被设计为线程安全。

答案 1 :(得分:0)

Ian的LinkedBlockingQueue解决方案是最简单的。

对于单个生产者单个消费者场景中的更高吞吐量(可能与延迟权衡),您可能需要考虑java.util.concurrent.Exchanger

中的示例

交换后,您现在可以自己拥有整个系列。

答案 2 :(得分:0)

如果有多个生产者在某个时间段内产生许多重复值 - 您可以尝试使用 ReadWriteLock,因为只要没有写入者,读取锁可能会被多个读取器线程同时持有。写锁是独占的。

即使在 readLock 内部,我们也在做写操作,但它仍然有效。更改名称或实现您自己的一对关联锁。

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class MyClass {

  private final Map<String, Integer> cachedData = new ConcurrentHashMap<>();
  private final ReadWriteLock lock = new ReentrantReadWriteLock();
  private final Lock readLock = lock.readLock();
  private final Lock writeLock = lock.writeLock();

  public void putData(String key, Integer value) {
    try {
      readLock.lock();
      cachedData.put(key, value);
    } finally {
      readLock.unlock();
    }
  }

  public Collection<Integer> copyAndFlush() {
    try {
      writeLock.lock();

      Collection<Integer> values = cachedData.values();
      cachedData.clear();

      return values;
    } finally {
      writeLock.unlock();
    }
  }
}