一、前言
关于项目中为什么不要使用System.out.println()的解释,网上有很多资料却并不准确或者详细,今天就其原因以及可能对项目造成的影响做深入剖析。
本篇文章氛围三个 要点,源码解析、影响分析、代码演示。
二、源码解析
打开println的源码,看到println方法体中有synchronized,也就是有锁的控制,换而言之就会出现阻塞的可能,后面我们会认为制造阻塞来演示。
如下图:
打开out源码,发现out用final static来修饰,也就是静态变量,可以认为在单机jvm中该变量全局唯一,如下图:
三、影响分析
通过以上两个图,我们可以想到有这么一种场景,在System.out.println()运行过程中,或因系统原因或者其它原因,导致在执行println的时候,发生了阻塞,那么因此带来的后果是,所有使用System.out.println()的地方,都会处于block状态,甚至引发系统宕机等。
至于System.out.println()本身的性能问题,可以作为单纯的性能优化来讲,也是不建议使用,既然是深入分析,我们先看下严重的场景,这才是导致禁用Syste.out.println()的重要原因。
四、代码模拟
我们根据源码,模拟这么一种场景,由于某种原因,System.out处于锁定状态,长时间没有释放,会引发什么。
模拟步骤:
1、新建两个线程:线程一和线程二
2、让线程一和线程二运行三秒后,开始对System.out进行锁定
3、查看线程一和线程二在System.out锁定时的打印情况及线程状态
4、释放System.out锁,在此查看线程一和线程二的运行情况
以下是测试代码:
package com.zhufeng.thread;
public class ZhufengDemo {
public static Object o = new Object();
public static void main(String[] args) throws InterruptedException {
ZhufengThread t1= new ZhufengThread("一");
ZhufengThread t2= new ZhufengThread("二");
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
System.out.println("3秒后对 System.out 加锁...");
Thread.sleep(3000);
//synchronized ( o){
synchronized ( System.out){
System.out.println("已经加锁...");
for(int i=10;i>0;i--){
System.out.println("倒计时:"+i+"——线程一状态:"
+thread1.getState()+",线程二状态"+thread2.getState());
Thread.sleep(1000);
}
}
System.out.println("锁已释放...");
}
}
此处运行逻辑是按照方才的说明步骤进行,线程中仅仅使用System.out.println进行打印,在System.out处于锁定状态时,查看两个线程是否会继续打印
package com.zhufeng.thread;
public class ZhufengThread implements Runnable {
private String name;
public ZhufengThread(String name){
this.name=name;
}
@Override
public void run() {
while (true){
System.out.println(name+"线程运行...");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程中每隔1.5秒打印一次。
我们运行打印程序,查看控制台日志:
结论:
通过控制台日志可以看到,线程一和线程二在运行过程中,如果System.out处于锁定时,两个线程处于BLOCKED状态,且不在进行打印,等待10秒System.out锁释放后,又开始重新执行打印。
所以说,生产上如果大量使用System.out.println(),将会对所有使用该语句的逻辑造成阻塞,影响不言而喻。