Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我的ConcurrentHashmap';s的值类型是List,如何使附加到该列表的线程安全?_Java_Scala_Concurrency_Thread Safety - Fatal编程技术网

Java 我的ConcurrentHashmap';s的值类型是List,如何使附加到该列表的线程安全?

Java 我的ConcurrentHashmap';s的值类型是List,如何使附加到该列表的线程安全?,java,scala,concurrency,thread-safety,Java,Scala,Concurrency,Thread Safety,我的类扩展自ConcurrentHashmap[String,immutable.List[String]] 它有两种方法: def addEntry(key: String, newList: immutable.List[String]) = { ... //if key exist,appending the newList to the exist one //otherwise set the newList as the value } def

我的类扩展自ConcurrentHashmap[String,immutable.List[String]]

它有两种方法:

  def addEntry(key: String, newList: immutable.List[String]) = {
    ...
    //if key exist,appending the newList to the exist one 
    //otherwise set the newList as the value
  }

  def resetEntry(key: String): Unit = {
    this.remove(key)
  }
为了使addEntry方法线程安全,我尝试了:

this.get(key).synchronized{
  //append or set here
}
但如果键不存在,则会引发空指针异常,并在同步之前使用putIfAbsent(键,new immutable.List())将不起作用,因为在putIfAbsent之后和进入同步块之前,该键可能会被resetEntry删除

使addEntry和resetEntry这两种同步方法都能工作,但锁太大

那么,我能做什么呢

另外,这篇文章和whileplz很相似,请帮我找出除了一般指南之外的其他编码方法

--更新--
签出,在将近3年多后解决了这个问题。

您能简单地清除条目而不是删除条目吗?您仍然可以使用同步列表并确保原子性

  def resetEntry(key: String, currentBatchSize: Int): Unit = {
    this.get(key).clear();
  }

这样做的前提是每个键都有一个条目。例如,如果
this.get(key)=null
,则需要插入一个新的
sychronizedList
,该列表也应充当clear。您可以尝试一种受CAS(比较和交换)过程启发的方法:

(在伪java scala代码中,因为我的scala仍处于初级阶段)


三年多以后,我想现在我可以回答我的问题了

最初的问题是:

我得到了一个
ConcurrentHashMap[String,List]
,许多线程都在向它添加值,如何使它成为线程安全的

使
addEntry()
同步将起作用,对吗

synchronize(map.get(key)){
  map.append(key, value)
}
在大多数情况下是,除非
map.get(key)
为null,这将导致NullPointerException

那么如何添加
map.putIfAbsent(键,新列表)
如下:

map.putIfAbsent(key, new List)
synchronize(map.get(key)){
  map.append(key, value)
}
class MyMap extends ConcurrentHashMap{
  val lock = new ReentrantReadWriteLock();  

  def addEntry(key: String, newList: immutable.List[String]) = {
    lock.readLock.lock()

    //if key exist,appending the newList to the exist one 
    //otherwise set the newList as the value
    this.putIfAbsent(key, new List())
    this(key).synchronized{
        this(key) += newList
    }

    lock.readLock.unlock()
  }

  def resetEntry(key: String, currentBatchSize: Int): Unit = {
    lock.writeLock.lock()

    this.remove(key)

    lock.writeLock.unlock()
  }
}
现在更好了,但是如果在
putIfAbsent()
另一个名为
resetEntry()
的线程之后,我们将再次看到NullPointerException

使addEntry和resetEntry都同步的方法可以工作,但锁太大

那么,追加时的MapEntry级别锁和重置时的Map级别锁呢

这是可重入的TreadWriteLock: 当调用
addEntry()
时,我们获取一个映射的共享锁,这使附加尽可能并发;当调用
resetEntry()
时,我们获取一个独占锁,以确保没有其他线程同时更改映射

代码如下所示:

map.putIfAbsent(key, new List)
synchronize(map.get(key)){
  map.append(key, value)
}
class MyMap extends ConcurrentHashMap{
  val lock = new ReentrantReadWriteLock();  

  def addEntry(key: String, newList: immutable.List[String]) = {
    lock.readLock.lock()

    //if key exist,appending the newList to the exist one 
    //otherwise set the newList as the value
    this.putIfAbsent(key, new List())
    this(key).synchronized{
        this(key) += newList
    }

    lock.readLock.unlock()
  }

  def resetEntry(key: String, currentBatchSize: Int): Unit = {
    lock.writeLock.lock()

    this.remove(key)

    lock.writeLock.unlock()
  }
}

但是我有成千上万个键,而且这个数字会不断增加,所以只要清除条目就会导致映射越来越大。因为remove+add不是原子指令,所以您必须在映射本身上同步以确保原子性。你确定有多余的键+一个空列表会消耗太多内存吗?另外,Viktor Klang在multimap impl上的一个有趣的要点(因此,将iso a列表设置为值)->@maasg仍在处理它,现在我采用Vint的方法:不是删除,而是清除它。至于键太多的问题,我想也许我可以安排另一个线程来锁定整个地图,以便在给定的时间间隔内清理密钥。@maasg通过使用ReadWriteLock,最终解决问题,签出