System.out.println을 실무에서 사용하면 안되는 이유

2024. 12. 5. 18:11·💻 Dev/Java & OOP

자바를 접하게 되면 제일 먼저 하는 것이 System.out.println("Hello, World!")일 것이다.
그만큼 기초이자, 아주 많이 사용하는 코드이다.
하지만 System.out.println은 실무에서 절대 사용하지 말라고들 한다.

 

왜일까?

성능 이슈로는 크게 2가지가 있다. 블로킹 I/O작업을 한다는 점과 멀티스레드에서 락이 발생한다는 점이다.

 

1. 블로킹 I/O 작업

먼저 System 클래스의 static 변수인 out은 PrintStream 타입의 인스턴스이다.

public static final PrintStream out = null;

그리고 PrintStream 클래스는 java의 io 패키지 내에 있다.

package java.io;

public class PrintStream extends FilterOutputStream  
    implements Appendable, Closeable

즉, println()은 I/O 작업이며 이는 프로그램이 데이터를 출력할 때 운영체제(OS)의 표준 출력 장치(콘솔 창, 터미널)로 데이터를 보내는 작업을 수행한다는 뜻이다.

 

이는 Blocking I/O 방식으로 동작하며 이는 데이터 출력 작업이 완료될 때까지 호출한 스레드가 블록(block)되어 다른 작업을 처리하지 못하는 방식을 의미한다.

 

2. synchronized 작업

표준 출력(System.out)은 공유 자원이기 때문에 여러 스레드에서 동시에 접근할 경우 출력 순서가 뒤섞이거나 충돌할 가능성이 있다.
이를 방지하기 위해 println 내부에선 snychronized 를 사용해 동기화 처리한다.
(String 뿐만 아니라 다른 매개변수도 비슷하다.)

public void println(String x) {  
    synchronized (this) {  
        print(x);  
        newLine();  
    }  
}

synchronized은 한 번에 하나의 스레드만 자원을 사용할 수 있도록 제한한다.
따라서 멀티스레드 환경에서 다수의 스레드가 동시에 로그를 출력하려고 하면 대기 시간이 증가하고 병목 현상이 발생한다.

 

즉, System.out.println()이 끝날 때까지 아무 일도 할 수 없고 대기해야 하기에 오버헤드가 발생해 성능이 저하되는 것이다.

 

+ 로그 레벨관리가 어려움

System.out.println은 로그의 중요도(DEBUG, INFO, WARN, ERROR 등)를 구분하지 못한다. 이는 프로덕션 환경에서 디버깅 메시지와 중요한 오류 로그가 섞이는 문제를 야기할 수 있다.

 

 

해결 방법은?

실무에서는 Log4j, SLF4J 같은 전문 로깅 프레임워크를 사용하는 것이 일반적이다.
디버깅 및 모니터링에 더 효과적이기 때문이다.


이 도구들은 로그를 별도의 스레드에서 처리해 병목 현상을 최소화하고, 로그의 중요도를 구분해 출력할 수 있다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
    private static final Logger logger = LoggerFactory.getLogger(MyClass.class);

    public static void main(String[] args) {
        logger.info("This is an INFO message.");
        logger.debug("This is a DEBUG message.");
        logger.error("This is an ERROR message.");
    }
}

 

 

 

 

 

참고
System.out.println() 사용을 자제해야 하는 이유
System.out.println 메소드는 실무에서 절대 사용하지 마라.

저작자표시 비영리

'💻 Dev > Java & OOP' 카테고리의 다른 글

자바는 왜 Lambda&Stream을 도입했을까? feat.함수형 프로그래밍  (0) 2024.12.26
리플렉션(Reflection)으로 DI 구현해보기 +단점  (0) 2024.12.22
Stack은 왜 상속의 실패 사례일까?  (0) 2024.12.12
가비지 컬렉터(GC)의 Roots  (0) 2024.12.04
Out-of-Memory(OOM)는 왜 발생하고, 어떻게 예방할까?  (0) 2024.11.30
instanceof 사용을 지양해야하는 3가지 이유  (0) 2024.11.29
'💻 Dev/Java & OOP' 카테고리의 다른 글
  • 리플렉션(Reflection)으로 DI 구현해보기 +단점
  • Stack은 왜 상속의 실패 사례일까?
  • 가비지 컬렉터(GC)의 Roots
  • Out-of-Memory(OOM)는 왜 발생하고, 어떻게 예방할까?
현주먹
현주먹
끄적끄적 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (162)
      • 👶🏻 CS (15)
        • Operating System (8)
        • Database (4)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • JPA (5)
        • Test Code (1)
        • Database (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (57)
        • 후기 및 회고 (5)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL
  • 인기 글

  • 태그

    코딩테스트준비
    til
    99클럽
    항해99
    티스토리챌린지
    오블완
    백준10250
    TDD 클린 코드 with Java
    백준
    인프런 단어뒤집기
    f-lab 후기
    자바의신절판
    F-Lab
    자바의정석
    개발자멘토링
    코테스터디
    오라클
    인프런 특정문자뒤집기
    로또 미션
    객체지향
    JPA
    PostGreSQL함수
    C
    데브클럽
    에프랩 후기
    에프랩
    jsp
    ==와 equals()
    NextSTEP
    개발자취업
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
현주먹
System.out.println을 실무에서 사용하면 안되는 이유
상단으로

티스토리툴바