Java 同步写入两个集合

Java 同步写入两个集合,java,concurrency,atomicity,Java,Concurrency,Atomicity,如果地图还不存在,我需要给它一些价值。键->值(如果设置)应始终位于两个集合中(即put应在两个映射中原子地出现)。我已尝试通过以下方式实现这一点: private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>(); private final ConcurrentMap<String, Object> map2 = new Concurrent

如果地图还不存在,我需要给它一些价值。键->值(如果设置)应始终位于两个集合中(即
put
应在两个映射中原子地出现)。我已尝试通过以下方式实现这一点:

private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>();
private final ConcurrentMap<String, Object> map2 = new ConcurrentHashMap<String, Object>();

public Object putIfAbsent(String key) {
    Object retval = map1.get(key);
    if (retval == null) {
        synchronized (map1) {
            retval = map1.get(key);
            if (retval == null) {
                Object value = new Object(); //or get it somewhere
                synchronized (map2) {
                    map1.put(key, value);
                    map2.put(key, new Object());
                }
                retval = value;
            }
        }
    }
    return retval;
}

public void doSomething(String key) {
    Object obj1 = map1.get(key);
    Object obj2 = map2.get(key);
    //do smth
}
private final ConcurrentMap map1=new ConcurrentHashMap();
私有最终ConcurrentMap map2=新ConcurrentHashMap();
公共对象putIfAbsent(字符串键){
Object retval=map1.get(key);
if(retval==null){
已同步(map1){
retval=map1.get(键);
if(retval==null){
Object value=new Object();//或者把它放到某个地方
已同步(map2){
map1.put(键、值);
map2.put(key,newobject());
}
retval=值;
}
}
}
返回返回;
}
公共void doSomething(字符串键){
对象obj1=map1.get(键);
对象obj2=map2.get(键);
//做smth
}
在所有情况下都可以吗?谢谢,有几个问题:

  • 不要使用“双重检查锁定”。一个快速的谷歌搜索将显示大量的文章,解释这种技术的问题。只需检查
    synchronized
    块内部
  • 您不需要在
    map1
    map2
    上同步。用一个或另一个
  • doSomething
    内同步。确保在
    putIfAbsent
    中用于同步的同一对象上进行同步
    • 一些问题:

      • 不要使用“双重检查锁定”。一个快速的谷歌搜索将显示大量的文章,解释这种技术的问题。只需检查
        synchronized
        块内部
      • 您不需要在
        map1
        map2
        上同步。用一个或另一个
      • doSomething
        内同步。确保在
        putIfAbsent
        中用于同步的同一对象上进行同步

      您不应该使用synchronized with ConcurrentHashMap(这几乎违背了目的)。对CHH进行原子添加的最佳方法是使用内置的替换方法。例如:

      do {
      
          oldValue1 = map1.get(key1);
          oldValue2 = map2.get(key2);
          newValue1 = // some logic to determine a new value for key1/value1
          newValue2 = // some more logic to determine a new value for key2/value2
      
      } while (!map1.replace(key1, oldValue1, newValue1) && !map2.replace(key2, oldValue2, newValue2));
      

      我不知道如何具体地将其应用到您的示例中,但这应该给您一个开始的地方。基本上是从映射中获取密钥,执行一些逻辑,如果密钥仍然与逻辑之前相同,它将替换条目并返回true,那么循环将中断。否则,它只会重复循环,直到它能够以原子方式进行更新。

      您不应该使用synchronized with ConcurrentHashMap(这几乎违背了目的)。对CHH进行原子添加的最佳方法是使用内置的替换方法。例如:

      do {
      
          oldValue1 = map1.get(key1);
          oldValue2 = map2.get(key2);
          newValue1 = // some logic to determine a new value for key1/value1
          newValue2 = // some more logic to determine a new value for key2/value2
      
      } while (!map1.replace(key1, oldValue1, newValue1) && !map2.replace(key2, oldValue2, newValue2));
      

      我不知道如何具体地将其应用到您的示例中,但这应该给您一个开始的地方。基本上是从映射中获取密钥,执行一些逻辑,如果密钥仍然与逻辑之前相同,它将替换条目并返回true,那么循环将中断。否则它只会重复循环,直到它能够以原子方式进行更新。

      为了完成您想要的操作,我将使用原子引用:

      class PairHolder {
         public final ConcurrentMap map1;
         public final ConcurrentMap map2;
         public PairHolder(...) // set values here.
      }
      
      private AtomicReference<PairHolder> mapHolder = ... // initialize it somehow
      
      do {
        PairHolder holder = mapHolder.get();
        ConcurrentMap map1 = holder.map1.clone()
        ConcurrentMap map2 = holder.map2.clone()
        newMap1.putIfAbsent(...);
        newMap2.putIfAbsent(...);
      } while (!mapHolder.compareAndSet(holder, new PairHolder(newMap1,newMap2))
      
      类配对器{
      公共最终同意图map1;
      公共最终同意图map2;
      public PairHolder(…)//在此处设置值。
      }
      私有原子引用映射持有者=…//以某种方式初始化它
      做{
      PairHolder holder=mapHolder.get();
      ConcurrentMap map1=holder.map1.clone()
      ConcurrentMap map2=holder.map2.clone()
      newMap1.putIfAbsent(…);
      newMap2.putIfAbsent(…);
      }而(!mapHolder.compareAndSet(holder,new PairHolder(newMap1,newMap2))
      

      通过这种方式,您可以始终确保mapHolder包含对PairHolder的引用,而PairHolder又有两个映射以100%原子方式更新。至少CAS应该保证这一点,但在多处理器系统上,这可能是错误的。

      为了满足您的要求,我会使用原子引用:

      class PairHolder {
         public final ConcurrentMap map1;
         public final ConcurrentMap map2;
         public PairHolder(...) // set values here.
      }
      
      private AtomicReference<PairHolder> mapHolder = ... // initialize it somehow
      
      do {
        PairHolder holder = mapHolder.get();
        ConcurrentMap map1 = holder.map1.clone()
        ConcurrentMap map2 = holder.map2.clone()
        newMap1.putIfAbsent(...);
        newMap2.putIfAbsent(...);
      } while (!mapHolder.compareAndSet(holder, new PairHolder(newMap1,newMap2))
      
      类配对器{
      公共最终同意图map1;
      公共最终同意图map2;
      public PairHolder(…)//在此处设置值。
      }
      私有原子引用映射持有者=…//以某种方式初始化它
      做{
      PairHolder holder=mapHolder.get();
      ConcurrentMap map1=holder.map1.clone()
      ConcurrentMap map2=holder.map2.clone()
      newMap1.putIfAbsent(…);
      newMap2.putIfAbsent(…);
      }而(!mapHolder.compareAndSet(holder,new PairHolder(newMap1,newMap2))
      

      通过这种方式,您可以始终确保mapHolder包含对PairHolder的引用,PairHolder又有两个映射100%原子更新。至少CAS应该保证这一点,但在多处理器系统上可能是错误的。

      好的,我终于找到了这个解决方案:

      private Map<String, Object> map1 = new HashMap<String, Object>();
      private Map<String, Object> map2 = new HashMap<String, Object>();
      
      private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      
      public void putIfAbsent(String key, Object o) {
          rwl.readLock().lock();
          try {
              if (map1.get(key) == null) {
                  rwl.readLock().unlock();
                  rwl.writeLock().lock();
                  try {
                      if (map1.get(key) == null) {
                          map1.put(key, getValue());
                          map2.put(key, getValue());
                      }
                  }finally {
                      rwl.readLock().lock();
                      rwl.writeLock().unlock();
                  }
              }
          } finally {
              readLock.unlock();
          }
      }
      
      public void readMap(String key) {
         rwl.readLock().lock();
          try {
             Object obj1 = map1.get(key);
             Object obj2 = map2.get(key);
          } finally {
              rwl.readLock().unlock();
          }
      
      }
      
      private Map map1=new HashMap();
      私有映射map2=新的HashMap();
      private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
      public void putIfAbsent(字符串键,对象o){
      rwl.readLock().lock();
      试一试{
      if(map1.get(key)==null){
      rwl.readLock().unlock();
      rwl.writeLock().lock();
      试一试{
      if(map1.get(key)==null){
      map1.put(key,getValue());
      map2.put(key,getValue());
      }
      }最后{
      rwl.readLock().lock();
      rwl.writeLock().unlock();
      }
      }
      }最后{
      readLock.unlock();
      }
      }
      公共void readMap(字符串键){
      rwl.readLock().lock();
      试一试{
      对象obj1=map1.get(键);
      对象obj2=map2.get(键);
      }最后{
      rwl.readLock().unlock();
      }
      }
      
      好的,我终于找到了这个解决方案:

      private Map<String, Object> map1 = new HashMap<String, Object>();
      private Map<String, Object> map2 = new HashMap<String, Object>();
      
      private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      
      public void putIfAbsent(String key, Object o) {
          rwl.readLock().lock();
          try {
              if (map1.get(key) == null) {
                  rwl.readLock().unlock();
                  rwl.writeLock().lock();
                  try {
                      if (map1.get(key) == null) {
                          map1.put(key, getValue());
                          map2.put(key, getValue());
                      }
                  }finally {
                      rwl.readLock().lock();
                      rwl.writeLock().unlock();
                  }
              }
          } finally {
              readLock.unlock();
          }
      }
      
      public void readMap(String key) {
         rwl.readLock().lock();
          try {
             Object obj1 = map1.get(key);
             Object obj2 = map2.get(key);
          } finally {
              rwl.readLock().unlock();
          }
      
      }
      
      private Map map1=new HashMap();
      私有映射map2=新的HashMap();
      private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
      公共场所