System.out.println and System.err.println out of order

后端 未结 7 1023
灰色年华
灰色年华 2020-11-22 03:44

My System.out.println() and System.err.println() calls aren\'t being printed to the console in the order I make them.

public static         


        
7条回答
  •  醉话见心
    2020-11-22 04:08

    This is caused by a feature in the JVM and unless you make a hack such as the one provided by Marcus A. it's not really that easy to work around. The .flush() works in this case but the reason for this is a lot more complicated to work around.

    What is happening here?

    When you program in Java you're not telling the computer straight what to do, you're telling the JVM (Java Virtual Machine) what you would want it to do. And it will do that, but in a more efficient manner. Your code isn't exact detailed instructions, in that case you'd only need a compiler like in C and C++, the JVM takes your code as a specification list for what it's supposed to optimise and then do. This is what's happening here. Java sees that you're pushing strings into two different buffer streams. The most efficient way of doing this is by buffering all the strings you want the streams to output and then output it. This happen one stream at the time, essentially transforming your code do something like this (beware: pseudo code):

    for(int i = 0; i < 5; i++) {
        out.add();
        err.add();
    }
    out.flush();
    err.flush();
    

    Because this is more efficient, this is what the JVM will do instead. Adding the .flush() in the loop will signal to the JVM that a flush needs to be done in each loop, which can't be improved with the above method. But if you for the sake of explaining how this works would have left out the loop, the JVM will reorder your code to have the printing done last, because this is more efficient.

    System.out.println("out");
    System.out.flush();
    System.err.println("err");
    System.err.flush();
    System.out.println("out");
    System.out.flush();
    System.err.println("err");
    System.err.flush();
    

    This code will always be re-organized to something like this:

    System.out.println("out");*
    System.err.println("err");*
    System.out.println("out");*
    System.err.println("err");*
    System.out.flush();
    System.err.flush();
    

    Because buffering many buffers only to flush them right after takes a lot more time than to buffer all the code to be buffered and then flush it all at the same time.

    How to solve it

    This is where code-design and architecture might come into play; you kinda don't solve this. To work around this, you have to make it more efficient to buffer print/flush, buffer print/flush than buffer all then flush. This will most likely be luring you into bad design. If it is important to you how to output it orderly, I suggest you try a different approach. For-looping with .flush() is one way to hack it, but you're still hacking the JVM's feature to re-arrange and optimize your code for you.

    * I can't verify that the buffer you added to first always will print first, but it most likely will.

提交回复
热议问题