RUKMANI SELVARAJ RUKMANI SELVARAJ - 1 month ago 12
Java Question

Is the scanner in java not thread safe?

I'm interested in using

java.util.Scanner
. I was reading the docs and saw a line saying A Scanner is not safe for multi threaded use without external synchronization. Can I confirm that this means that two separate Scanner objects in two separate threads operating on two separate files could interfere with each other?

Can anyone help me to synchronise scanner object externally to use for safe thread operation?

Answer

If you use the same instance of Scanner in two threads you will have trouble unless you synchronise access to the object. But two separate instances of Scanner will never interfere with each other.

edit in response to comment asking how to synchronise

First, are you really sure you need to synchronise at all? You can safely use different scanner instances in different threads without any danger. One thread can have
Scanner s1 = new Scanner (new File ("/tmp/file1.txt");
and another thread can have
Scanner s2 - new Scanner (new File ("/tmp/file2.txt"));
and there is no risk. The different scanners can use the same file, different files or completely different data sources. You still need to be cautious though. As noted by Stephen C below you will still get broken operation if two separate instances of Scanner are using the same stream or reader as their input then they will steal characters from each other. This warning applies to the constructors using InputStream, Readable and ReadableByteChannel.

The problem with using a single scanner in multiple threads is that it is sequentially consuming characters from a single source. If you have multiple threads consuming these characters in unsynchronised fashion then each thread will get some of the characters and none of the threads will get all of the characters. To illustrate: Imagine you have a scanner reading the string "qwertyuiop", and two separate threads each call function next() at the same time, then one thread might see "ertip" and the other thread would get "qwyuo"; which would be useless.

My suggestions to synchronise this are:

  1. Do not multi-thread! Even amputation of body parts is preferrable to trying to make a multi-threaded application stable, scalable and flexible!
  2. Sometimes you can subclass a non-thread-safe class (or encapsulate and delegate) and synchronise calls to the base class (or delegate): synchronised (this) { super.next (); }. But don't try this with Scanner! There are so many consumer methods, and you have no idea how the class is implemented internally so you are doomed to fail! See suggestion 1.
  3. What I would try to do here is have a single thread running the Scanner and feeding the tokens into an ArrayBlockingQueue. That way you will get complete tokens going into the queue in their correct order. You can have as many threads as you like reading from the queue. But be aware that any of your threads can get blocked either reading or writing this queue unless you take care to handle full and empty conditions. Chances are that no matter what you do you will end up with dangling threads that never finish. See point 1. This will get complicated if you want to sometimes call different next methods (e.g. nextInt(), nextDouble()) or use the has methods (e.g. hasNextInt(), hasNextDouble()), but not as complicated as point 2.

Finally, I would suggest you see point 1.