I guess you would be using System.out.println
for output to the console and new Scanner(System.in);
for reading input.
Essentially System.out
is a PrintStream
and System.in
is a InputStream
and are different object (and streams) but they both use same source (I guess IDE console or command prompt in your case) so when 2 or more threads will try to use the same source then you will get the behavior you have mentioned because by default same source/console is used by the host environment or user. Read below from Java source:
System.out
/**
* The "standard" input stream. This stream is already
* open and ready to supply input data. Typically this stream
* corresponds to keyboard input or another input source specified by
* the host environment or user.
*/
System.in
/**
* The "standard" output stream. This stream is already
* open and ready to accept output data. Typically this stream
* corresponds to display output or another output destination
* specified by the host environment or user.
As far as I know, there are really no such API's to help you out what you are looking for but there are couple of work around options:
Please note, IMHO Option 3 or any similar solution which is based on synchronization is something which you may not want because it will limit your output'ing capabilities
Option 1:
Configure a different console device and then access it using System.console()
. In this case, you will have different sources for read and write to console and hence you will not get what you are seeing. If you don't explicitly configure anything then by default you will get System.console()
as NULL
Option 2:
Instead of writing the output to console, use a file to write the output. This will ensure that your input and output stream are not messing up with each other.
Option 3:
If you have same source for both read and write to console, then synchronize the access. Below is same code but please be mindful that you could still see some overlap for the time when object lock is being acquired and released but once lock is acquired or released on System.out
or System.in
then you will not see overlap.
public class Test {
static Object object = new Object();
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
Date date = new Date();
System.out.println("I am coming from first thread i.e. " + Thread.currentThread().getId() + " : " + date);
}
}
}
}.start();
new Thread(){
@Override
public void run() {
Scanner scanner = new Scanner(System.in);
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
scanner.next();
}
}
}
}.start();
}
}