Multithreading – what is the best Scala thread safe way to write to bufferedwriter?
I have a simple way to write a line of data to a file followed by a new line executed asynchronously
def writeToFile(bw: BufferedWriter,str: String) = {
bw.write(str)
bw.newLine
}
When my program runs, due to the asynchronous nature of the call, I get "mixed" lines in the file For example... Say writetofile (BW, "foo") is executed asynchronously three times. I may get:
Correct output
May be wrong
I can avoid this possibility by using this synchronized method:
def writeToFile(bw: BufferedWriter,str: String) = synchronized {
bw.write(str)
bw.newLine
}
Based on my research, I'm not sure how "secure" this is for extending my application The only example I can use synchronized lookup is when accessing a collection, not when writing to a file My application is built in play! Frame 2.4 two
Solution
Personally, I will create an akka actor for each bufferedwriter, which will completely encapsulate it
import java.io.BufferedWriter
import akka.actor._
import playground.BufferedWriterActor.WriteToBuffer
object BufferedWriterActor {
val name = "BufferedWriterActor"
def props(bw: BufferedWriter) = Props(classOf[BufferedWriterActor],bw)
case class WriteToBuffer(str: String)
}
class BufferedWriterActor(bw: BufferedWriter) extends Actor {
def receive: Actor.Receive = {
case WriteToBuffer(str) =>
bw.write(str)
bw.newLine()
}
}
Use it like this:
import akka.actor.{ActorSystem,Props}
object HelloWorld {
def main(args: Array[String]): Unit = {
val system = ActorSystem("mySystem")
// Share this actor across all your threads.
val myActor = system.actorOf(BufferedWriterActor.props(bw),BufferedWriterActor.name)
// Send messages to this actor from all you threads.
myActor ! BufferedWriterActor.WriteToBuffer("The Text")
}
}
This links all calls to this buffer in a single thread
More information about akka and his actors is here:
http://akka.io/
http://doc.akka.io/docs/akka/snapshot/scala/actors.html
The playback framework itself uses akka, so you should be able to use its default actor system, but I don't remember what happened
