Why println ran before printStackTace?

Asked

Viewed 98 times

6

I was studying Exception Treatment in Java and I came to this question that I could not find on Google.

Why in this example he printed the first line of the printStackTrace, and already gave the println, and then the rest of the printStackTrace?

Exemplo de Código

  • When you log many things at the same time (I know in your case it was just an instruction), it can happen from one message to "cross" the other...

  • Look at this question http://stackoverflow.com/questions/19460987/why-is-system-out-prinln-out-of-order

2 answers

10


At first an operating system works with 3 rows System.err (flow output for standard error stderr), System.out (standard flow output stdout) and System.in (stdin data input)

When using the PrintStackTrace, he writes by default on System.err and also informs a cell trace, ie the chain of methods that led to the exception.

In a simple Java console application, both outputs (System.err and System.out) will be the same (application console) but you can reconfigure the streams for example System.out print on the console and System.err write to a file for example.

With respect to order, both run in the same sequence, but the operating system can randomly choose which queue to print first (stderr or stdout).

for example

public static void main(String[] args) {
    System.out.println("stdout -> 1");
    System.out.println("stdout -> 2");
    System.out.println("stdout -> 3");
    System.err.println("stderr -> 1");
    System.err.println("stderr -> 2");
    System.err.println("stderr -> 3");
}

in this code snippet I send 3 instructions to stdout and 3 to stderr, they will be executed in sequence, but each queue can take random order by OS.

You will see that at each run it will change the order of the queues but the instruction order for the queue will not, the printing for stdout follow the sequence (1, 2, 3) and to stderr also (1, 2, 3) but the order it will display the queue will not respect this sequence (stdout, stderr)

There is a way to synchronize the two queues, however it is a kind of hack:

public class ConsoleHackTools {

    private static OutputStream lastStream = null;
    private static boolean isFixed = false;

    private static class FixedStream extends OutputStream {

        private final OutputStream target;

        public FixedStream(OutputStream originalStream) {
            target = originalStream;
        }

        @Override
        public void write(int b) throws IOException {
            if (lastStream != this)
                swap();
            target.write(b);
        }

        @Override
        public void write(byte[] b) throws IOException {
            if (lastStream != this)
                swap();
            target.write(b);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            if (lastStream != this)
                swap();
            target.write(b, off, len);
        }

        private void swap() throws IOException {
            if (lastStream != null) {
                lastStream.flush();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                }
            }
            lastStream = this;
        }

        @Override
        public void close() throws IOException {
            target.close();
        }

        @Override
        public void flush() throws IOException {
            target.flush();
        }
    }

    public static void fixConsole() {
        if (isFixed)
            return;
        isFixed = true;
        System.setErr(new PrintStream(new FixedStream(System.err)));
        System.setOut(new PrintStream(new FixedStream(System.out)));
    }
}

With this hack, changing the example of sysout and earlier syserr would look like this:

public static void main(String[] args) {
    ConsoleHackTools.fixConsole();

    System.out.println("stdout -> 1");
    System.out.println("stdout -> 2");
    System.out.println("stdout -> 3");
    System.err.println("stderr -> 1");
    System.err.println("stderr -> 2");
    System.err.println("stderr -> 3");
}

In this code, you will see that now yes the application will respect the sequence stdout (1, 2, 3), stderr (1, 2, 3) and also the sequence of the queues (stdout, stderr)

  • Does the fact that sometimes a "cross over" message on the console mean that there is some sort of competition between Threads when the S.O. will print on the console? For example, can he try to print messages from different queues at the same time and shuffle them? That’s what happens?

  • 2

    this, let’s say that each queue (Stdout and Stderr) are processed in different threads, it can happen that the Stdout thread write on the console at the same time as the Stderr is writing or the other way around, this management is on account of the OS, or through the above hack, basically this "hack" tries to leave the action of these two threads in jvm "Synchronous"

  • In the documentation: Optionally, a PrintStream can be created so as to flush automatically; this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written. Then the print order will depend on the behavior of System.out and System.err in the JVM implementation you are using, without being too sure when each stream will print. You can force the immediate printing by calling the flush() method on out and err

  • It makes sense what Brow-joe said, I remembered from the O.R..

3

Operating systems have two main output streams: standard output or STDOUT and standard error or STDERR (accessed in java by Streams System.out and System.err). Error messages, for example the printStackTrace you used in the code, are printed in STDERR.

When you open a terminal, by default you see the two being printed simultaneously, but they are independent and so the order they are printed may vary. You can redirect the outputs to analyze them independently. For example on Linux, to reset the default output to the file resultado.txt and the default error for the file erro.txt

java Metodo1 > resultado.txt 2> erro.txt

In the archive resultado.txt I would have:

Acabou o Programa!

Already in the archive erro.txt:

SenhaInvalidaException: Senha Inválida!
    at Metodo1.autenticar(Metodo1.java:15)
    at Metodo1.main(Metodo1.java:4)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.