再使用System.out.println()打印收拾东西回家
创始人
2025-07-03 10:02:04
0

一、前言

今天没事干的时候,无意间点到了一个System.out.println()中的println()方法,一个闪亮的关键字冲击着我的眼睛。

不知道大家知不知道,那就是加锁的synchronized。但凡有锁的地方肯定会性能是有损耗的,当然得在并发的情况下!

synchronized在JDK8还是6之后进入了锁升级概念:无锁--->偏向锁--->自旋锁--->轻量级锁--->重量级锁

「轻量级锁和偏向锁通常不涉及内核态切换」

「在到重量级锁时涉及到用户态和内核态的切换,很影响性能的!」

有兴趣的可以自己研究一下synchronized的锁升级和降级!

下面我们回归正题,看一下这个System.out.println()!

二、源码和分析

网上文章很多,大家想看System和out的详细解读,可以去看看哈,这里主要看一下println()这个方法的源码!

public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
}

我们以传进来的是Object对象为例,其他类型比这个少了一个转化为String在输出!

这种方式通常被称为对象级别的锁,因为它是以对象为粒度进行同步的!

print(s);newLine();这两个操作在同一时间只被一个线程执行,以防止输出的内容被多个线程交织在一起,导致输出混乱。

这种同步是为了保证输出的可见性和一致性。当然也带来了性能的损耗,一般情况不会引起线程阻塞,当多个线程尝试同时访问同一个控制台输出时,由于控制台输出的同步性质,可能会导致线程竞争锁,从而导致程序响应慢!

当然在没有并发的场景中,使用一下也没什么,切记不要在输出里面加上大量的运算和转换逻辑。

「但是为了不给后期埋雷,咱们还是尽量不要使用。」

「可以使用专门的日志框架,如Log4j、Logback等,它们提供了更灵活的日志记录和输出控制。」

我们在查看一下: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;
    }
}

里面的textOut.flushBuffer()也是有锁的!

void flushBuffer() throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (nextChar == 0)
            return;
        out.write(cb, 0, nextChar);
        nextChar = 0;
    }
}

我们在看一下ensureOpen()方法,然后一直点就会发现 write(String chars, int start, int count)也是加着锁的!

所以我们还是不要轻易在项目中使用哈,「咱们还是使用日志框架」,还能有不用的日志级别打印,多香!

每天一个小技巧哈!

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);
    }
}

三、缺点和方案

1、缺点

性能问题

使用 System.out.println() 输出信息到控制台通常比内存操作和计算操作慢得多。这是因为控制台输出涉及到文件I/O操作,需要将数据写入控制台。在高性能的应用程序中,频繁的输出会导致程序的性能下降,特别是在大规模数据处理和高并发情况下。

缺乏日志级别

System.out.println() 不支持不同的日志级别(如DEBUG、INFO、ERROR等),因此无法将输出信息分类为不同的重要性。在生产环境中,通常需要能够根据日志级别过滤和记录信息。

无法集中管理日志

System.out.println() 输出的信息通常散落在代码的各个地方,不容易集中管理。在实际应用中,通常需要将日志集中存储和管理,以便日后的监控、分析和故障排查。

2、方案

我们上面也是说了,这里在强调一遍哈:

建议使用专门的日志框架来管理和控制日志输出,一些流行的 Java 日志框架包括:Log4j、Logback、SLF4J...

四、总结

虽然 System.out.println() 在快速测试和学习阶段很有用,但在实际的应用程序中,频繁使用它可能会导致一系列问题。

因此,建议在生产环境中使用专门的日志框架来管理和控制日志输出,以便更好地满足应用程序的需求,并提高代码的可维护性和可扩展性。

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Intel将Moblin社区控... 本周二,非营利机构Linux基金会宣布,他们将担负起Moblin社区的管理工作,而这之前,Mobli...