szefuf
szefuf

Reputation: 520

Atomic copy-and-clear on Java collection

I know similar questions are often asked, but I could not find anything that would help me.

The situation is like this:

The thing is: how to copy (I think it's best to work on copy) the collection for second worker, and then clear original collection to ensure we won't lost anything (the first worker is writing all the time) but not to hold lock on original collection as short as possible?

thanks

Upvotes: 2

Views: 1785

Answers (3)

Serg
Serg

Reputation: 235

works for me

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 sharedLock = lock.readLock();
  private final Lock copyAndFlushLock = lock.writeLock();

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

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

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

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

Upvotes: -1

Kelvin Ng
Kelvin Ng

Reputation: 174

Ian's LinkedBlockingQueue solution is the simplest.

For higher throughput (potentially trade off with latency) in a single producer single consumer scenario, you may want to consider the example in java.util.concurrent.Exchanger

After swapping, you now have the whole collection yourself.

Upvotes: 0

Ian Roberts
Ian Roberts

Reputation: 122364

This kind of thing will be far easier if you use the purpose-built concurrency tools like LinkedBlockingQueue rather than a plain HashSet. Have the producer add elements to the queue, and the consumer can use drainTo to extract elements from the queue in batches as it requires them. There's no need for any synchronization, as BlockingQueue implementations are designed to be threadsafe.

Upvotes: 10

Related Questions