慎用 System.out.println( ) 之 性能测试

一. 缘由

这两天在验证问题的时候, 突然发现一个问题System.out.println( ) 会影响测试的准确性,

因为System.out.println( ) 本来性能就很差!!!!!!

所以特意做了个性能测试.

 

二.测试代码

测试代码很简单,我就在两个代码之间增加了一行System.out.println(). 然后测试对性能的影响.

package com.system;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.Options;

import java.util.*;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime) // 测试完成时间
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) // 预热 2 轮,每次 1s
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 1s
@Fork(2) // fork 2 个线程
@State(Scope.Thread) // 每个测试线程一个实例
public class SystemTest {

    public static void main(String[] args) throws RunnerException {
        // 启动基准测试
        Options opt = new OptionsBuilder()
                .include(SystemTest.class.getSimpleName()) // 要导入的测试类
//                .output("/a/jmh-map.log") // 输出测试结果的文件
                .build();
        new Runner(opt).run(); // 执行测试
    }


    @Benchmark
    public void nullFor() {
        for (int i = 0 ; i < 100 ; i++){
            String x = String.valueOf(i) ;
        }
    }

    @Benchmark
    public void OutFor() {
        for (int i = 0 ; i < 100 ; i++){
            System.out.println(i);
        }
    }


}

测试结果:

Benchmark           Mode  Cnt        Score         Error  Units
SystemTest.OutFor   avgt   10  1894854.560 ± 1519929.208  ns/op
SystemTest.nullFor  avgt   10     1692.085 ±     200.099  ns/op

 

三. 源码分析

 里面大量用到了 synchronized 关键字, 所以这个是同步执行的,

当有大量的并发或者使用的时候, synchronized 会造成锁升级. 当锁膨胀为重量级锁的时候,对系统性能的影响是灾难性的!!!!!!

    /**
     * Prints an integer and then terminate the line.  This method behaves as
     * though it invokes {@link #print(int)} and then
     * {@link #println()}.
     *
     * @param x  The int to be printed.
     */
    public void println(int x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
    private void write(String s) {
        try {
            synchronized (this) {
                ensureOpen();
                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;
        }
    }
    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;
        }
    }

 

 

 

 

 

 

 

 

你可能感兴趣的:(性能测试)