简体   繁体   中英

Java concurrency support using java.util.concurrent semantics

I'm trying to support modification (deactivate() function call) of the following data structure in a thread safe manner -

 private static Map<String, Set<Integer>> dbPartitionStatus = new HashMap<String, Set<DBPartitionId>>();

 public void deactivate(DBPartitionId partition) throws Exception {
    synchronized (dbPartitionStatus) {
        Set<DBPartitionId> partitions = dbPartitionStatus.get(serviceName);
        if (partitions == null) {
            partitions = new HashSet<DBPartitionId>();
        }
        partitions.add(partition);
        dbPartitionStatus.put(serviceName, partitions);
    }
}

If I were to replace the synchronization with ConcurrentHashMap & ConcurrentSkipListSet duo, there would be some race condition.

I was wondering if there was a cleaner way of achieving synchronization here (using java.util.concurrent)

Should be no race conditions with the following implementation:

private final static ConcurrentMap <String, Set <DBPartitionId>> dbPartitionStatus = 
    new ConcurrentHashMap <String, Set <DBPartitionId>> ();

public void deactivate (DBPartitionId partition) {
    Set <DBPartitionId> partitions = dbPartitionStatus.get (serviceName);
    if (partitions == null)
    {
        partitions = new ConcurrentSkipListSet <DBPartitionId> ();
        Set <DBPartitionId> p = 
            dbPartitionStatus.putIfAbsent (serviceName, partitions);
        if (p != null) partitions = p;
    }
    partitions.add (partition);
}

I personally cannot see a issues with this sort of approach:

private static ConcurrentHashMap<String, ConcurrentSkipListSet<DBPartitionId>> dbPartitionStatus = new ConcurrentHashMap<>();

public bool deactivate(DBPartitionId partition) throws Exception {
  ConcurrentSkipListSet<DBPartitionId> partitions = dbPartitionStatus.get(serviceName);
  if (partitions == null) {
    // Create a new set
    partitions = new ConcurrentSkipListSet<DBPartitionId>();
    // Attempt to add, if we add, ev will be null.
    ConcurrentSkipListSet<DBPartitionId> ev  = dbPartitionStatus.put(serviceName, partitions);
    // If non-null, someone else has added it, so now use it.
    if (ev != null)
      partitions = ev;
  }
  // will return true if added succesfully...
  return partitions.add(partition);
}

There is also the putIfAbsent() method in map which can do the get/put onthe map in an "atomic" operation, however it has the additional overhead in this case that you have to construct an empty set to pass in each time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM