System.out.println() 메서드는 Java 개발 시 디버깅 용도로 콘솔에 출력하는 메소드 중 하나이다
System은 java.lang 패키지의 내장되어있는 최종 클래스이다
out 은 System의 정적(static) 멤버 필드이다
그리고 System.out 은 PrintStream의 인스턴스(객체/구현한 것)이다
println() 메서드를 내부적으로 살펴보면 다음과 같다

이곳만 보면 모든 내용을 이해할 수 없다
그리고 오늘은 동기화, 스레드 에 관한 내용을 보고자하기 때문에
PrintStream의 newLine 메서드의 내부구조를 살펴봤다

내부를 살펴보면 lock , synchronized 라는 키워드가 나온다
위에 말했듯이 두 키워드는 동기화와 관련된 키워드이다
동기화란 무엇일까?
간단히 설명하자면, 프로세스는 시스템을 처리하는 단위인데, 여러 개의 프로세스가 동시에 공유된 자원(데이터)에 동시에 접근하기 될 때 문제가 발생할 수 있다
무작위로 접근하는 Thread 들이 하나의 자원에 경쟁하듯 접근하는 경쟁상태(Race Condition)가 발생할 수 있고, 여러 프로세스가 하나의 데이터에 접근하면 데이터가 의도한 바와 다른 값으로 처리될 수 있기 때문이다
이러한 문제를 해결하기 위해 한 번에 하나의 프로세스만 접근할 수 있도록 제한을 두는 동기화 작업이 필요하다
자바의 synchronized 키워드는 동기화 기능을 제공한다
메소드나 블록에 적용하여 한 번에 하나의 스레드만 실행할 수 있다
이때 lock 을 거는 작업과, 해제하는 작업을 통해서 이루어진다
lock이 실행되면 lock을 건 스레드만 실행된다
이 방식은 lock을 걸고 자신을 실행하는 스레드, 깨우는 스레드, 경쟁하는 스레드들 의 세 종류의 스레드로 설명할 수 있다
println() 메서드는 synchronized 기능이 있기 때문에 많은 단점을 가진다
1. 메서드가 실행될 때마다 lock 기능이 실행되기 때문에 메서드 실행 끝까지 다른 스레드들이 대기해야해서 성능 저하를 일으킨다
2. println()은 Java 개발시 디버깅 용도로 콘솔에 출력하는 메소드인데, 디버그의 중요도에 대한 기능이 없어 관리가 어렵다
3. 출력 메시지의 위치에 따라 리팩토링, 유지보수가 어려울 수 있다
4. 콘솔창에 출력하는 기능만 있기 때문에 나중에 다시 확인할 수 없다
위와 같은 문제점을 해결하는 대안으로는 로그(log)하는 방식이 있다
로깅은 앱 개발 시 운영 중 발생하는 문제점을 모니터링하거나 추적하기 위해 기록을 남기는 것이다
단, 잘못 사용하면 작업이 방대하게 몰리거나 무의미한 로그가 쌓여 성능저하를 일으킬 수 있다
스프링 부트(Spring Boot) 는 JCL(Jakarta(Apache) Commons Logging)이라는 추상화 라이브러리를 제공한다
추상화되어있기때문에 개발자가 로깅 라이브러리 구현체를 선택하거나 선택, 교체할 수 있다
문제점은 런타임 시점에서 JCL 구현체 선택하기 때문에 런타임 시점에 메소드 영역(Static/Method Area)에 Java 클래스를 로드하는 클래스 로더에 의존적이라는 것이다
클래스 로더에 로드된 리소스는 힙 영역(Heap Area)에서 일어나는 가비지컬렉션(Garbage Collection)에 포함되지 않아 GC가 일어나지 않고 메모리 누수(Memory Leak)가 발생한다
그에 대한 대안에는 SLF4J(Simple Logging Facade for Java)가 있다
Bridging, API, Binding 모듈 제공하며 컴파일 단계에서 구현체를 선택할 수 있다
*Binding: 어댑터 역할을 하며 SLF4J API 인터페이스와 로깅 구현체를 연결한다
*Bridging: 로거 호출을 SLF4J 인터페이스로 연결한다
Logger란 log를 기록하는 프로세스인 로깅에 사용되는 소프트웨어 구성요소이다
위에 말했던 디버깅 기능을 위해 심각도 수준(log level)을 지원한다(DEBUG, INFO, WARNING, ERROR, CRITICAL 등)
개발자가 로그 메시지의 형식 지정하고, 콘솔, 파일, DB, 또는 네트워크를 통해 다양한 출력에 저장할 수 있다
로그 레벨(Log Level)은 스프링 프레임워크에서 로그 메시지의 중요도를 나타낸다
로깅 시스템의 설정을 통해 지정되고, 설정된 로그 레벨 이상의 중요도를 가진 로그 메시지만 기록한다
아래 7가지 단계로 흔히 분류되지만 보통 1~6 단계까지만 사용된다고 한다
0) ALL
1) TRACE: 가장 상세한 로그 레벨, 애플리케이션의 실행 흐름과 디버깅 정보 상세히 기록, 디버깅 시에 사용
2) DEBUG: 디버깅 목적으로 사용, 개발 단계에서 상세한 정보 기록, 애플리케이션 내부 동작 이해, 문제 분석에 도움 준다
3) INFO: 정보성 메시지 기록, 애플리케이션의 주요 이벤트나 실행 상태에 대한 정보 전달
4) WARN: 경고성 메시지 기록, 예상치 못한 문제나 잠재적인 오류 상황을 알리는 메시지, 애플리케이션이 정상적으로 동작하지만 주의가 필요한 상황을 알림
5) ERROR: 오류 메시지 기록, 심각한 문제 또는 예외 상황을 나타냄, 애플리케이션의 정상적인 동작에 영향을 미칠 수 있는 문제 알림
6) FATAL: 가장 심각한 오류 메시지 기록, 애플리케이션의 동작으르 중단시킬 수 있는 치명적인 오류를 나타냄, 복구가 불가능하거나 매우 어려운 상황의 오류
7)OFF
System.out.prinln()은 자바를 공부하는 사람이라면 누구나 쉽게 사용하고, 기본적인 메소드라고 생각해 자세히 들여다 볼 일이 없었다
그러나 락을 걸고, 다른 프로세스가 실행되지 때문에 디버깅 용도에 적합하지 않다는 것을 알 수 있었다
또한 그 대안으로 Spring Boot 의 log 기능에 대해서 알 수 있었다
앞으로 배울 Spring Boot는 Java를 기반으로 하며 프로그램을 개발하기 위해 사용되는 틀을 제공하는 프로그램이다
다양한 라이브러리를 제공하기 때문에 다형성을 구현할 수 있고, 따라서 배울 수 있는 것들이 많을 것 같다
앞으로도 차근차근 화이팅하자 ~
'[Kotlin&Spring] 5기 내일배움캠프' 카테고리의 다른 글
| [Kotlin&Spring] 5기 계산기 과제 트러블슈팅 - Java의 Optional 클래스 (0) | 2025.01.10 |
|---|---|
| [Kotlin&Spring] 5기 Enum에 대해 DB에서 바라보기 (1) | 2025.01.08 |
| [Kotlin&Spring] 5기 Enum 열거형에 대해 (0) | 2025.01.06 |
| [Kotlin&Spring] 5기 얕은 복사와 깊은 복사 - 배열(Array) (2) | 2025.01.03 |
| [Kotlin&Spring] 5기 논리 연산자와 비트 이동 연산자(shift) (1) | 2025.01.02 |