Kevin Meredith
Kevin Meredith

Reputation: 41909

Scala Singleton Object with Multi-threading

Using play, my Controller calls the Foo service, an object. This object, which uses val's and immutable data structures only, will be called by multiple clients.

When my Controller calls Foo.doQuery() in multiple threads, what will happen?

If client 1 makes a call that performs Foo.doQuery(), will client 2's call to Foo.doQuery() have to wait?

I'm curious if I should simply create a new class per instance of Foo, but I'd like to know what happens with a Scala singleton, using val's only, in a multi-threaded environment.

Upvotes: 8

Views: 5733

Answers (2)

Remis Haroon - رامز
Remis Haroon - رامز

Reputation: 3572

To illustrate @harp seal pup's answer, here is an example demo with output,
We can observe the mutable variable myname is affected by each running thread.
But the immutable val thname is not affected or locked for each thread.

object ObjectMultiThreadingTest {

  def main(args: Array[String]): Unit = {

    for (x <- 1 to 5) {
      var thread = new MyThread()
      thread.setName("Thread number :" + x.toString)
      thread.start()
    }
  }

  class MyThread extends Thread {
    override def run(): Unit = {
      Singleton.myname = this.getName
      Singleton.call(this.getName)
    }
  }

  object Singleton {
    var myname = "Singleton"
    def call(threadName: String): Unit = {
      val thName = threadName
      val random = new Random
      for (i <- 1 to 5) {
        println("My Name is set by " + myname)
        val sleeptime = random.nextInt(1000)
        println(
          "But, I am now running " + thName + ", sleeping for " + sleeptime
        )
        Thread.sleep(sleeptime)
      }
    }

  }
}

output:

My Name is set by Thread number :5
My Name is set by Thread number :5
My Name is set by Thread number :5
But, I am now running Thread number :3, sleeping for 498
My Name is set by Thread number :5
My Name is set by Thread number :5
But, I am now running Thread number :5, sleeping for 968
But, I am now running Thread number :4, sleeping for 232
But, I am now running Thread number :2, sleeping for 562
But, I am now running Thread number :1, sleeping for 204
My Name is set by Thread number :5
But, I am now running Thread number :1, sleeping for 315
My Name is set by Thread number :5
But, I am now running Thread number :4, sleeping for 100
My Name is set by Thread number :5
But, I am now running Thread number :4, sleeping for 749
My Name is set by Thread number :5
But, I am now running Thread number :3, sleeping for 66
My Name is set by Thread number :5
But, I am now running Thread number :1, sleeping for 4
My Name is set by Thread number :5
But, I am now running Thread number :1, sleeping for 332
My Name is set by Thread number :5
But, I am now running Thread number :2, sleeping for 899
My Name is set by Thread number :5
But, I am now running Thread number :3, sleeping for 679
My Name is set by Thread number :5
But, I am now running Thread number :1, sleeping for 849
My Name is set by Thread number :5
But, I am now running Thread number :5, sleeping for 157
My Name is set by Thread number :5
But, I am now running Thread number :4, sleeping for 694
My Name is set by Thread number :5
But, I am now running Thread number :5, sleeping for 864
My Name is set by Thread number :5
But, I am now running Thread number :3, sleeping for 591
My Name is set by Thread number :5
But, I am now running Thread number :2, sleeping for 702
My Name is set by Thread number :5
But, I am now running Thread number :4, sleeping for 339
My Name is set by Thread number :5
But, I am now running Thread number :3, sleeping for 959
My Name is set by Thread number :5
But, I am now running Thread number :5, sleeping for 443
My Name is set by Thread number :5
But, I am now running Thread number :2, sleeping for 522
My Name is set by Thread number :5
But, I am now running Thread number :5, sleeping for 368
My Name is set by Thread number :5
But, I am now running Thread number :2, sleeping for 851

Upvotes: 0

harp seal pup
harp seal pup

Reputation: 504

No, a Scala object doesn't imply a lock ('synchronized' in java), so the client 2 doesn't have to wait. Both client 1, client 2 and client n can run concurrently if you don't explicitly add locks to the code.

Think of

object MyObject { ... }

as

class MyClass(..) { ... }
lazy val MyObject = new MyClass(..)

A lock can be applied with the 'synchronized' function like this:

def doQuery = synchronized {
  ..
  ..
}

== EDIT ==

As for your question in the comment, the thread (or call) stack and variable sharing have nothing to do with your controller using immutable references and/or immutable data structures. What matters is where you define your variables. If you define a variable, be it a val or var, inside a method (method variable), then every time the method is called, that variable is created just for the calling thread. On the other hand, if you define your variable at the class or object level (instance variable), all calls to the instance method always share the same instance variable.

In your case, I think you can implement your controller as a singleton object since immutable references and data structures are well.. immutable. It doesn't matter if they're shared or not.

Upvotes: 12

Related Questions