Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-threading in Scala -- dealing only with immutability

I have the code of Scala

class MyClass {
  private val myData: Map[String, MyClass2] = new HashMap[String, MyClass2]()

  def someMethod = {
      synchronized(myData) {
        val id = getSomeId
        if (myData.containsKey(id)) myData = myData.remove(id)
        else Log.d("123", "Not found!")
      }
  }

  def getSomeId = //....
}

I wonder, is it possible to remain this code thread-safe without using synchronized and without involving some other libraries such Akka or any other libraries (classes) even built-in in Java or Scala?

Ideally, I'd like to make thread-safe only by using the conception of immutability (final in Java, if you will).

UPDATE:

class MyClass(myData: Map[String, MyClass2] = new HashMap[String, MyClass2]()) {

  def someMethod = {
      synchronized(myData) {
        val id = getSomeId
        if (myData.containsKey(id)) new MyClass(myData.remove(id))
        else {
           Log.d("123", "Not found!")
           this
         }
      }
  }

  def getSomeId = //....
}
like image 253
Alan Coromano Avatar asked Feb 17 '23 05:02

Alan Coromano


1 Answers

You can solve the problem with immutability only if you make MyClass immutable too (and let it use only immutable data structures as well). The reason is simple: If MyClass is mutable, then you have to synchronize modifications by concurrent threads.

This requires a different design - every operation that causes an instance of MyClass to "change" will instead return a (possibly) modified instance.

import collection.immutable._

class MyClass2 {
  // ...
}

// We can make the default constructor private, if we want to manage the
// map ourselves instead of allowing users to pass arbitrary maps
// (depends on your use case):
class MyClass private (val myData: Map[String,MyClass2]) {
  // A public constructor:
  def this() = this(new HashMap[String,MyClass2]())

  def someMethod(id: String): MyClass = {
    if (myData.contains(id))
      new MyClass(myData - id) // create a new, updated instance
    else {
      println("Not found: " + id)
      this // no modification, we can return the current
            // unmodified instance
    }
  }

  // other methods for adding something to the map
  // ...
}
like image 108
Petr Avatar answered Feb 23 '23 06:02

Petr