Java映射:多线程杂耍者

Java映射:多线程杂耍者,java,multithreading,collections,map,concurrency,Java,Multithreading,Collections,Map,Concurrency,我面临着以下问题: 我有许多异步读者和作者。jdk有没有为我的案例提供线程安全的实现?据我所知,ConcurrentHashMap不适合有许多异步编写器的情况 如果我需要同步彼此之间的两个并发映射,我可以在没有完全同步的情况下实现吗?(我的意思是不在每个方法中添加synchonized关键字) 我读了你的评论,决定重新表述我的问题 想象一下这种情况,您必须: //Singleton public class Container { public ConcurrentHashMap<

我面临着以下问题:

  • 我有许多异步读者和作者。jdk有没有为我的案例提供线程安全的实现?据我所知,ConcurrentHashMap不适合有许多异步编写器的情况
  • 如果我需要同步彼此之间的两个并发映射,我可以在没有完全同步的情况下实现吗?(我的意思是不在每个方法中添加synchonized关键字)

  • 我读了你的评论,决定重新表述我的问题

    想象一下这种情况,您必须:

    //Singleton
    public class Container {
       public ConcurrentHashMap<String, MyObj> map1 = new ConcurrentHashMap<String, MyObj>();
       public ConcurrentHashMap<String, MyObj> map2 = new ConcurrentHashMap<String, MyObj>();
    
       public void replaceForward(String key) {
         Object value = map1.remove(key);
         map2.put(key, value);
       }
    
       public void replaceBackward(String key) {
         MyObj value = map2.remove(key);
         map1.put(key, value);
       }
    
       //This operation should be as quick as possible!
       public void replaceAllForward(int criteria) {
         for (Map.Entry<String, MyObj> entry entry : map1.entrySet()) {
           if (entry.getValue().criteria = criteria) {
             replaceForward(entry.getKey()); 
           }
         }
       }
    
       //This operation should be as quick as possible!
       public void replaceAllBackward(String key) {
         //just the same but from map2 to map1
       }
    
       public void remove(String key) {
          map1.remove(key);
       }
    
       public void add(String key, MyObj value) {
          map2.put(key, value);
       }
    
       //This operation should be as quick as possible!
       public Map<String, MyObj> getByCriteria(int criteria) {
         ConcurrentHashMap<String, MyObj> resultMap = new ConcurrentHashMap<String, MyObj>();
         for (Map.Entry<String, MyObj> entry entry : map1.entrySet()) {
           if (entry.getValue().criteria = criteria) {
             resultMap.put(entry.getKey(), entry.getValue); 
           }
         }
         return resultMap;
       }
    }
    
    //单例
    公营货柜{
    public ConcurrentHashMap map1=新的ConcurrentHashMap();
    public ConcurrentHashMap map2=新的ConcurrentHashMap();
    公共void replaceForward(字符串键){
    对象值=映射1。删除(键);
    map2.put(键、值);
    }
    public void replaceBackward(字符串键){
    MyObj值=map2.删除(键);
    map1.put(键、值);
    }
    //此操作应尽可能快!
    公共void replaceAllForward(整数标准){
    对于(Map.Entry:map1.entrySet()){
    if(entry.getValue().criteria=criteria){
    replaceForward(entry.getKey());
    }
    }
    }
    //此操作应尽可能快!
    公共void replaceAllBackward(字符串键){
    //相同,但从map2到map1
    }
    公共无效删除(字符串键){
    map1.删除(键);
    }
    public void add(字符串键,MyObj值){
    map2.put(键、值);
    }
    //此操作应尽可能快!
    公共映射getByCriteria(int标准){
    ConcurrentHashMap resultMap=新的ConcurrentHashMap();
    对于(Map.Entry:map1.entrySet()){
    if(entry.getValue().criteria=criteria){
    resultMap.put(entry.getKey(),entry.getValue);
    }
    }
    返回结果图;
    }
    }
    
    您有两个线程,都使用这些映射进行操作

    Thread1:
    map1
    中的元素替换为
    map2
    (我的意思是从
    map1
    中删除并放到
    map2

    Thread1:
    map2
    中的元素替换为
    map1


    问题:它是线程安全的吗?

    与您的示例中的ConcurrentHashMap类似,如果您编写:

    V value = map1.remove(key);
    if (value != null) map2.put(key, value);
    
    您可以保证不会有任何项目“丢失”,也不会有任何项目被多次添加到map2,即使存在多个读写器

    但是,在很短的时间内,键/值将不在map1或map2中。对于您的用例来说,这可能是问题,也可能不是问题

    replaceAllForward
    中,您迭代一个映射并将内容移动到另一个映射。在这里,移动将安全地进行,但如果同时添加了一些项目,则可能会在原始地图的末尾留下一些项目


    如何使
    getAllByCriteria
    更快

    这取决于你地图的大小。如果它很小的话,你可能不会做得更好。如果它更大,您可以将作业并行化

    使用Java 8,您可能会通过以下方式获得更好的性能:

    public Map<String, MyObj> getByCriteria(int criteria) {
      return map1.entrySet()
          .parallelStream() //this is your speedup
          .filter(e -> e.getValue().criteria = criteria)
          .collect(toConcurrentMap(Entry::getKey, Entry::getValue));
    }
    
    publicmap getByCriteria(int-criteria){
    返回map1.entrySet()
    .parallelStream()//这是您的加速比
    .filter(e->e.getValue().criteria=标准)
    .collect(toConcurrentMap(Entry::getKey,Entry::getValue));
    }
    

    在Java 8之前,您可以自己编写并行算法,看看它是否能提高性能。

    “ConcurrentHAshMap不适合有许多异步编写器的情况。”=>您为什么会这样想?请详细说明2中的含义。?地图之间的关系是什么?@assylias我刚听说。我错了吗?@VolodymyrBakhmatiuk ConcurrentHashMap正是为此而设计的:多个读写器。现在的问题是这是否是原子的,不是吗?1)你的意思是它是绝对线程安全的吗?2) 如何使
    getAllByCriteria
    更快?@VolodymyrBakhmatiuk这再次取决于您需要什么样的线程安全性。如果您需要确保条目始终位于map1或map2中,则不安全。如果您确定在移动时,条目既不在map1中也不在map2中,那么它是安全的。换句话说,这取决于类的不变量应该是什么。@VolodymyrBakhmatiuk关于第二个问题,请参阅我的编辑。谢谢解释。不可以实体既不在map1中也不在map2中是不可以的。我该怎么办?也许有一种方法可以将这两张地图表示为一张?(但在这种情况下,我必须有一种快速的方法从求和映射中提取submap1和submap2)如果不锁定,我看不到明显的解决方案。。。你可以围绕这个具体问题问一个新问题。