线程安全地更新Scala集合 [英] Updating Scala collections thread-safely

查看:140
本文介绍了线程安全地更新Scala集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有任何简单的方法来安全地更新不可变的scala集合。考虑下面的代码:

  class a {
private var x = Map [Int,Int]()

def update(p:(Int,Int)){x = x +(p)}
}

这段代码不是线程安全的,正确吗?我的意思是,如果我们有两个线程调用update方法,让我们说x是map包含{1 => 2}和线程A调用update((3,4)),并且只设法执行x +(p)部分代码。然后重新调度发生,线程B调用update((13,37))并成功更新变量x。线A继续并完成。



完成所有这些操作后,值x将等于包含{1 => 2,3 => 4}的映射,是否正确?代替期望的{1 => 2,3 => 4,13 => 37}。有一个简单的方法来解决这个问题吗?我希望它是undestandable我要求:)



Btw,我知道有解决方案像Akka STM,但我宁愿不使用那些,除非必要。非常感谢任何答案!



编辑:此外,我宁愿解决方案没有锁定。 Eeeew:)

解决方案

在你的情况下,正如Maurício写的,你的集合已经是线程安全的,因为它是不可变的。唯一的问题是重新分配 var ,这可能不是原子操作。对于这个特定的问题,最简单的选择是使用 java.util.concurrent.atomic 中的nice类,即 AtomicReference

  import java.util.concurrent.atomic.AtomicReference 

class a {
private val x = new AtomicReference(Map [Int,Int]())

def update(p:(Int,Int)){
while(true){
val oldMap = x.get //获取旧值
val newMap = oldMap + p //更新
if(x.compareAndSet(oldMap,newMap))
return // exit if update已成功,否则重复
}
}
}


i was wondering if there is any 'easy' way to update immutable scala collections safely. Consider following code:

class a {
   private var x = Map[Int,Int]()

   def update(p:(Int,Int)) { x = x + (p) }
}

This code is not thread safe, correct? By that i mean that if we have two threads invoking update method and lets say that x is map containing { 1=>2 } and thread A invokes update((3,4)) and only manages to execute the x + (p) part of the code. Then rescheduling occurs and thread B invokes update((13,37)) and successfully updates the variable x. The thread A continues and finishes.

After all this finishes, value x would equal map containing { 1=>2, 3=>4 }, correct? Instead of desired { 1=>2, 3=>4, 13=>37 }. Is there a simple way to fix that? I hope it's undestandable what I'm asking :)

Btw, i know there are solutions like Akka STM but i would prefer not to use those, unless necessary.

Thanks a lot for any answer!

edit: Also, i would prefer solution without locking. Eeeew :)

解决方案

In your case, as Maurício wrote, your collection is already thread safe because it is immutable. The only problem is reassigning the var, which may not be an atomic operation. For this particular problem, the easiest option is to use of the nice classes in java.util.concurrent.atomic, namely AtomicReference.

import java.util.concurrent.atomic.AtomicReference

class a {
  private val x = new AtomicReference(Map[Int,Int]())

  def update(p:(Int,Int)) {
    while (true) {
      val oldMap = x.get // get old value
      val newMap = oldMap + p // update
      if (x.compareAndSet(oldMap, newMap))
        return // exit if update was successful, else repeat
    }
  }
}

这篇关于线程安全地更新Scala集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆