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