Reputation: 41909
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
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
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