System.out.println()标准输出方法性能影响一窥

来源:互联网 发布:php全站搜索 编辑:程序博客网 时间:2024/06/07 09:14

System.out.println()标准输出方法性能影响一窥

#

以前在写功能性代码的时候就知道,代码功能性的强大往往意味着性能的丢失。

那么非常好用支持任何格式输出到控制台的System.out.println()标准输出方法究竟是如何工作的呢?


做一个简单的测试

public class TestOut {    private static long timeOut = System.currentTimeMillis() + 1000L;    private static void outQuick() {    long i = 1L;    while (timeOut >= System.currentTimeMillis()) {        i++;    }    System.out.println(i);    }    private static void outOnlyNumber() {    long i = 1L;    while (timeOut >= System.currentTimeMillis()) {        System.out.println(i++);    }    }    private static void outOnlyString() {    long i = 1L;    while (timeOut >= System.currentTimeMillis()) {        System.out.println(""+i++);    }    }    public static void main(String[] args) {    outQuick();    //outOnlyNumber();    //outOnlyString();    }}

首先测试的没有使用标准输出方法的运算,得到的结果稳定在2亿4千万次到2亿七千万次左右,下面给出几次结果

256908210241685465271216750259256219

第二次测试的打印数字,执行结果大概在17万到25万之间,其中大多数为17万左右

170775160830175684251080

第三次测试打印把数字转成字符然后再输出,执行结果稳定在20万以上

276857252494230742291023

得到以下几条信息

  1. System.out.println()标准输出方法对性能的影响导致执行效率下降了1500倍左右
  2. System.out.println()标准输出方法使用字符串输出时执行效率只下降1000倍左右

为什么会这样呢?

看看源码,发现System.out.println()标准输出方法的执行过程是这样的

/**  * 参数不同会调用不同的构造方法     * Prints a String and then terminate the line.  This method behaves as     * though it invokes <code>{@link #print(String)}</code> and then     * <code>{@link #println()}</code>.     *     * @param x  The <code>String</code> to be printed.     */    public void println(String x) {        synchronized (this) {            print(x);            newLine();        }    }/**  * 如果是一个对象,则会多一句代码String s = String.valueOf(x);     * Prints an Object and then terminate the line.  This method calls     * at first String.valueOf(x) to get the printed object's string value,     * then behaves as     * though it invokes <code>{@link #print(String)}</code> and then     * <code>{@link #println()}</code>.     *     * @param x  The <code>Object</code> to be printed.     */    public void println(Object x) {        String s = String.valueOf(x);        // 该方法是一个synchronized的方法,首先打印字符,然后换一行。        synchronized (this) {            print(s);            // newLine()也是一个synchronized的方法            newLine();        }    }/**  * 多出的这一句代码实质上是调用了对象的toString()方法并做了空判断     * Returns the string representation of the {@code Object} argument.     *     * @param   obj   an {@code Object}.     * @return  if the argument is {@code null}, then a string equal to     *          {@code "null"}; otherwise, the value of     *          {@code obj.toString()} is returned.     * @see     java.lang.Object#toString()     */    public static String valueOf(Object obj) {        return (obj == null) ? "null" : obj.toString();    }/**  * 也许你以为newLine()方法只是打印一个\n,但是实际上,他却是这样的     * 其中textOut.flushBuffer();也是一个synchronized方法     * 如果在这个过程中发生了IO中断异常,newLine()方法会中断掉当前线程     */private void newLine() {        try {            synchronized (this) {                ensureOpen();                textOut.newLine();                textOut.flushBuffer();                charOut.flushBuffer();                if (autoFlush)                    out.flush();            }        }        catch (InterruptedIOException x) {            Thread.currentThread().interrupt();        }        catch (IOException x) {            trouble = true;        }    }/**  * 将输出缓冲区刷新到基础字符流     * Flushes the output buffer to the underlying character stream, without     * flushing the stream itself.  This method is non-private only so that it     * may be invoked by PrintStream.     */    void flushBuffer() throws IOException {        synchronized (lock) {            ensureOpen();            if (nextChar == 0)                return;            out.write(cb, 0, nextChar);            nextChar = 0;        }    }/**  * 打印字符,如果字符不为空的话     * Prints a string.  If the argument is <code>null</code> then the string     * <code>"null"</code> is printed.  Otherwise, the string's characters are     * converted into bytes according to the platform's default character     * encoding, and these bytes are written in exactly the manner of the     * <code>{@link #write(int)}</code> method.     *     * @param      s   The <code>String</code> to be printed     */    public void print(String s) {        if (s == null) {            s = "null";        }        write(s);    }/**  * 输出字符的write方法和newLine动作其实是一致的     * System.out.println()标准输出方法其实相当于print()方法调用两次     */private void write(String s) {        try {            synchronized (this) {                ensureOpen();                // textOut是BufferedWriter的一个对象,该类继承至Object以及Writer类                // 该类是一个抽象类,作用是向字符流中执行写入。                textOut.write(s);                textOut.flushBuffer();                charOut.flushBuffer();                if (autoFlush && (s.indexOf('\n') >= 0))                    out.flush();            }        }        catch (InterruptedIOException x) {            Thread.currentThread().interrupt();        }        catch (IOException x) {            trouble = true;        }    }/**  * textOut.write(s);调用的是该方法     * 但是该方法只是把字符拆分一些信息来传递参数     * Writes a string.     *     * @param  str     *         String to be written     *     * @throws  IOException     *          If an I/O error occurs     */    public void write(String str) throws IOException {        write(str, 0, str.length());    }/**  * 该方法也是synchronized的     * lock其实是this,通过this.lock=this获得     * Writes a portion of a string.     *     * @param  str     *         A String     *     * @param  off     *         Offset from which to start writing characters     *     * @param  len     *         Number of characters to write     *     * @throws  IndexOutOfBoundsException     *          If <tt>off</tt> is negative, or <tt>len</tt> is negative,     *          or <tt>off+len</tt> is negative or greater than the length     *          of the given string     *     * @throws  IOException     *          If an I/O error occurs     */    public void write(String str, int off, int len) throws IOException {        synchronized (lock) {            char cbuf[];            if (len <= WRITE_BUFFER_SIZE) {                if (writeBuffer == null) {                    writeBuffer = new char[WRITE_BUFFER_SIZE];                }                cbuf = writeBuffer;            } else {    // Don't permanently allocate very large buffers.                cbuf = new char[len];            }            str.getChars(off, (off + len), cbuf, 0);            write(cbuf, 0, len);        }    }
原创粉丝点击