Java Interview 대비

JVM, GC, OOP, API, JDBC

Posted by iheese on December 07, 2023 · 25 mins read

JVM의 구조와 Java의 실행방식을 설명해주세요

  • JVM(Java Virtual Machine), 자바와 운영체제 사이의 중개자 역할을 한다. 가비지 컬렉터를 사용한 메모리 관리도 자동으로 수행하고, 스택 기반으로 동작한다.
    • 덕분에 운영체제에 구애받지 않고 프로그램을 실행할 수 있다.
  • 실행방식
    1. 자바 컴파일러(javac)에 의해 자바 소스 파일(.java)이 바이트 코드(.class)로 변환된다.
    2. Class Loader를 통해 class 파일들을 JVM 메모리의 메소드 영역으로 로딩한다.
    3. 로딩된 class 파일들은 Excution engine을 통해 실행된다.
  • 구조 :
    • Class Loader : JVM 내로 클래스 파일을 로드, 링크를 통해 배치하는 작업을 수행하는 모듈, 런타임 시 동적으로 로드한다.
    • Garbage Collector : 힙 메모리 영역 참조되지 않은 객체 탐색 후 제거한다.
    • Execution Engine : Runtime Data Area에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.
      • 인터프리터 방식에서 JIT 컴파일러 방식으로 보완되었다.
        • JIT 컴파일러는 반복되는 코드를 발견하면 바이트 코드를 어셈블리어 같은 네이티브 코드로 바꿉니다. 실행이 빠르지만 변환 비용이 비교적 크게 발생한다.
        • 그러므로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고 인터프리터 방식을 사용하다가 일정 기준이 넘어가면 JIT 컴파일러 방식으로 실행한다.
    • Runtime Data Area : 자바 애플리케이션이 실행될 때 사용되는 데이터들을 적재하는 영역이다. (Method Area, Heap Area, Stack Area, PC Register, Native Method Stack)


JVM 메모리 구조에 대해 알고 있나요?

  • JVM 메모리는 Runtime Data Area에 저장이 되며 메소드 영역, 힙 영역, 스택 영역, PC레지스터 영역, 네이티브 메소드 스택 영역으로 나누어집니다.
    • 메소드 영역 : 모든 스레드가 공유하며 바이트코드로 변환된 것들을 저장합니다.(클래스, 인터페이스, 메소드, 필드, static 변수 등)
    • 힙 영역 : 모든 스레드가 공유하며, new 키워드로 생성된 객체와 배열이 저장되는 영역입니다. 클래스 영역에 로드된 클래스로 생성이 가능하고 GC가 참조되지 않는 메모리를 확인하고 제거합니다.
    • 스택 영역 : 메소드 호출 마다 스택 프레임(그 메소드를 위한 공간)이 생성됩니다. 메소드 안에서 사용되는 값(매개변수, 지역변수, 리턴 값 연산 시 일어나는 값)을 저장하고 메소드 수행이 끝나면 프레임별로 삭제합니다.
    • PC 레지스터 : 스레드가 시작될 때 생성되며, 스레드마다 하나씩 존재합니다. 스레드가 어떤 명령으로 실행해야 할 지에 대한 기록을 하는 부분으로 JVM 명령의 주소를 갖습니다.
    • 네이티브 메소드 스택 영역 : 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역입니다.


JIT(Just-In-Time) 컴파일러에 대해 알고 있나요?

  • JVM의 Execution Engine에서 런타임 시 바이트 코드를 기계어로 변환하여 실행할 때 인터프리터를 이용합니다. 하지만 컴파일 언어에 비해 성능이 매우 떨어지게 됩니다. 이 때 사용되는 것이 JIT 컴파일러입니다.
  • 자주 실행되는 바이트 코드 영역을 런타임 중에 기계어로 컴파일하여 사용하는 것입니다.
  • 같은 코드를 매번 해석하지 않고 실행할 때 컴파일하면서 해당 코드를 캐싱해버린다. 이후에는 바뀐 부분만 컴파일한다.


GC가 무엇인지, 필요한 이유는 무엇인지, 동작방식에 대해 설명해주세요.

  • GC(Garbage Collection), 힙 영역에서 사용하지 않는 객체들을 제거하는 작업을 총징한다. 자바 언어는 개발자가 메모리를 직접 해제하는 언어가 아니기 때문이 이 작업은 꼭 필요하다.
  • GC의 영역
  • 아래서 설명하는 GC의 구조와 동작 방식은 Serial GC 기준이다.
    • Minor GC : young 영역, 새롭게 생성된 객체가 할당 되는 영역, 먾은 객체가 Young 영역에 생성되었다 사라집니다.
      • eden 1개, survivor 2개로 구성되어 있다. eden 영역이 가득차면 survivor로 넘어가면서 실행된다.
      • 크기가 작아서 GC 시간이 작다.
    • Major GC : old 영역, 특정 횟수 이상을 살아남은 참조 변수가 살아있는 곳입니다.
      • survivor 2번쨰까지 들렸다가 사용되면 Old 영역으로 오게된다.
      • Old 영역이 가득차면 Major GC가 발생한다.
  • GC의 동작 방식
    • Stop The World : GC를 수행하기 위해 JVM이 어플리케이션의 실행을 멈추는 작업을 말합니다. GC를 실행하는 스레드를 제외한 모든 스레드들의 작업이 중단되고 GC가 완료되면 작업이 재개됩니다.
      • 스레드의 작업이 중단되면 어플리케이션이 멈추기 때문에 GC 성능 튜닝을 한다고 하면 이 부분의 시간을 줄이는 작업을 말합니다.
      • 특히 Old 영역은 크기가 크기 때문에 Major GC 시간이 오래걸린다.
    • Mark And Sweep : 모든 작업이 중단되면 GC는 스택의 모든 변수 또는 Reachable 객체(어디선가 사용하고 있는 객체, Unreachable : 아무도 사용하지 않고 자리만 차지하고 있는 객체)를 스캔하면서 각각 어떤 객체를 참조하고 있는지 탐색하게 됩니다. 그리고 사용되고 있는 메모리를 식별하고 사용되지 않는 객체를 제거합니다.
  • [JAVA] Garbage Collection의 개념과 동작 원리


GC의 종류와 차이점

  • Serial GC : GC를 싱글 스레드로 처리, stop-the-world 시간이 긴 편
    • young 영역에서는 Mark-sweep, old 영역에서는 Mark and Sweep Compact 알고리즘 사용
      • compact는 Heap 영역을 정리하기 위한 단계로 유효한 객체들이 연속되게 쌓이도록 힙의 앞부터 채우게 하는 것이다.
  • Parallel GC : java8의 default GC, Minor GC에서 멀티 스레드 동작, Serial GC과 기본적인 처리과정이 같다.
  • Parallel Old GC : Major GC에서 멀티 스레드 동작, Minor GC는 Mark and Sweep Compact, Major GC는 Mark Summary Compact 알고리즘 사용
    • Mark Summary Compact 알고리즘 : Summary 단계에서 살아있는 객체를 식별한다는 점에서 조금 더 복잡하다.
  • CMS (Concurrent Mark and Sweep) GC : Mark and Sweep Compact 개선하여 멀티스레드로 사용하여 Stop the world 시간 개선했으나, 다른 GC보다 CPU, 메모리 소모량이 커서 메모리 할당이 어려워지면 다른 방식보다 더 긴 Stop the world 발생
    • GC와 프로세서의 리소스를 공유하기 때문이다. 어플리케이션 응답이 늦어질 수 있지만 GC에 의해 어플리케이션이 정지되지 않는다.
    • java14 부터 사용 중지
  • G1(Garbage First) GC : java 9부터 default GC, 힙 영역을 동일한 사이즈의 지역으로 나누고 Eden, Survior, Old, Available/Unused, Humongous는 역할을 수행합니다. Multi core CPU, 대용량 메모리 시스템을 위한 GC
    • Eden : 다른 GC의 Eden 역할과 같은 역할, 새로 생긴 객체들이 할당.
    • Survivor : 살아있는 객체들이 할당.
    • Old : 오래 살아있는 객체들이 할당.
    • Humongous : Region 크기의 50%가 넘는 큰 객체들을 할당.
    • Available/Unused : 아직 사용되지 않는 영역.
  • Young-Only, Space Reclamation 이 반복되는 Cycle 구조
    • Minor GC만 수행하다가 Old Generation 비율이 넘으면 Major GC 실행, 그리고 Young Only 끝날 때까지 함께 작동
    • Space Reclamation 단계는 Mixed GC 방식 작동, Mixed GC 는 Minor GC 처럼 움직이고 Old 영역의 Garbage까지 수 집한다.
  • Z GC : JDK 15버젼에서 바로 Production Ready, 조금 더 큰 메모리(8MB ~ 16TB) 에서 효율적으로 Garbage Collect 하기 위한 알고리즘, G1과 다르게 동일한 사이즈로 분할하지 않는 것이 다르다.
    • Z GC 를 실행시키고 싶다면 java -XX:+UseZGC -jar Application.java
  • JDK 17 기준 CPU 1개면 Serial GC, CPU 2개 이상이몀 G1 GC 가 실행된다. (JDK 9 이후 동일, 기본 설정값)
  • Java GC Gargabe Collection 알짜만 빼먹기 / 알고리즘 / 종류 / 모니터링 VisualVM
  • VM과 Garbage Collection - G1GC vs ZGC


오버라이딩과 오버로딩이 무엇이며 어떤 차이가 있을까요?

  • 오버라이딩 : 상위 클래스의 메소드를 재정의하는 것을 의미한다.(런타임 다형성)
    • 이름, 매개변수, 리턴타입이 같고, 메소드 내용이 달라야 한다.
  • 오버로딩 : 같은 클래스 내 동일한 메소드 이름을 가지지만 매개변수의 타입, 갯수를 다르게 구현할 수 있는 것을 의미한다. (컴파일 다형성)
    • 메소드 이름이 같아야 하며, 매개변수 갯수, 타입이 달라야 한다.
    • 리턴타입만 다르면 성립이 되지 않고, 매개변수와 함께 달라져야 성립된다.


객체지향 프로그래밍에 대해서 설명해주세요.

  • 모든 데이터를 객체 취급하며, 처리 요청을 받은 객체는 객체 내부 기능을 사용해 요청을 처리합니다.
  • 특징으로 캡슐화, 상속, 다형성, 추상화가 있습니다. 모듈 재사용성이 좋아 확장 및 유지보수가 용이합니다.
    • 캡슐화 : 클래스 내부 변수와 메소드를 하나로 패키징하는 것
      • 정보 은닉 : 객체 내부 구현을 숨김으로써 객체가 반드시 정해진 메소드를 통해 상호작용하도록 유도하는 것
      • 접근 제어자를 통해 구현
        • public : 다른 객체에서 해당 객체 인스턴스 생성하여 접근 가능
        • protected : 해당 객체를 상속받은 객체 내부에서 접근 가능
        • default : 동일한 패키지 내의 객체에서 인스턴스 생성하여 접근 가능
        • private : 선언된 객체 내부에서만 사용 가능
    • 상속 : 보통 하위 클래스가 상위 클래스를 상속 받게 됩니다. 상속받은 하위 클래스는 상위 클래스의 변수와 메소드를 사용할 수 있게 되고 메소드를 오버라이딩하여 사용할 수 있게 됩니다. 코드의 재사용성이 높아지고 중복을 줄일 수 있게 됩니다.
    • 다형성 : 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의마합니다. 부모 클래스의 참조변수로 자식 클래스의 인스턴스를 참조할 수 있게 구현합니다.
    • 추상화 : 공통된 부분을 뽑아서 상위 클래스로 뽑아내는 것을 의미힙니다. 중복 코드를 줄일 수 있고, 재사용성을 높이고 가독성을 상승시킬 수 있다.


try-with-resource에 대해서 설명해주세요.

  • 자바7 이전에 try-catch-finally의 문제점으로 개발자가 close()를 통해 마지막에 자원을 해제시켜주는 것을 누락하거나, 자원 해제를 해줘도 중복 코드가 발생하기 때문에 가독성을 해치는 단점이 있었다.
  • 자바 7 이후에 try(객체 선언)을 해주면 로직 처리 여부와 상관없이 JVM에서 자원을 해제시켜주는 기능이다.
  • 자바 9 부터는 try 문 밖에서 객체를 선언하고 인스턴스 변수를 넣는 형태로 바뀌었다.


API란?

  • Application Progamming Interface
  • API는 프로그램들이 서로 상호작용하는 것을 도와주는 매개체
    • 서버와 데이터베이스에 대한 출입구 역할을 한다.
  • 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻한다.


JDBC API이란

  • Java DataBase Connectivity의 줄임말, 자바 프로그램 내에서 DB 상관없이 DB와 관련된 작업을 처리해주는 API이다.


SOLID(객체지향 5대원칙)에 대해서 설명해주세요.

  • SRP(Single Responsibility Principle, 단일 책임 원칙) : 한 클래스는 하나의 책임만 가져야 합니다. 즉 클래스는 그 책임을 완전히 캡슐화해야 함을 말한다.
    • 한 클래스는 한 가지 책임에 관한 변경사항이 생겼을 때만 코드를 수정하게 되는 구조가 좋은 구조
    • 한 책임의 변경으로의 연쇄작용에서 자유로울 수 있다.
    • 코드 가독성 향상, 유지보수 용이, 다른 설계 원칙을 적용하는 기초
    • 좋은 프로그램은 응집도를 높게, 결합도는 낮게
      • 응집도 : 한 프로그램 요소가 얼마나 뭉쳐있는가를 나타내는 척도, 결합도 : 프로그램 구성 요소들 사이가 얼마나 의존적인지를 나타내는 척도
  • OCP(Open Closed Principle, 개방 폐쇄 원칙) : 확장에는 열려 있어야 하나 변경에는 닫혀 있어야 합니다. 이를 적용하기 위한 중요 메커니즘은 추상화와 다형성입니다.
    • 추상화 사용을 통한 관계 구축을 권장을 의미한다.
    • EX) OCP 원칙의 가장 잘 따르는 예시 : JAVA 데이터베이스 인터페이스인 JDBC이다.
  • LSP(Liskov Substitution Principle, 리스코프 치환 법칙) : 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 합니다. 상위 타입을 상속해서 재정의했을 대 프로그램에 에러가 없어야 합니다.
    • 다형성 원리를 이용하고자 하는 원칙 개념이다.
    • EX) Collection 인터페이스 : 자료형을 바꿔서 메소드를 실행해도 잘된다. 즉 다형성을 이용해 부모 타입 메소드를 실행해도 의도대로 잘 실행된다.
  • ISP(Interface Segregation Principle, 인터페이스 분리 원칙) : 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안되는 원칙입니다. 범용 인터페이스 보다는 여러 개의 인터페이스로 분리해야합니다.
    • SRP는 클래스의 단일 책임, ISP는 인터페이스의 단일 책임을 강조한다.
    • 인터페이스는 다중 구현이 가능하기 때문에 클라이언트의 목적과 용도에 적합한 인터페이스만을 제공하는 것을 의미한다.
  • DIP(Dependency Inversion Principle, 의존관계 역전 원칙) : 추상적인 것은 구체적인 것에 의존하지 않고, 변화하기 쉬운 것에 의존하면 안된다는 것입니다. 구체적으로는 구현 클래스에 의존하지 말고 인터페이스에 의존해야 하는 원칙입니다.
    • DIP를 따르는 인기 있는 방법은 DI(의존성 주입)을 활용하는 것이다.
    • 어떤 클래스를 참조해서 사용해야 하는 상황이 생긴다면 직접 클래스를 잡조하는 것이 아니라 그 대상 상위 요소(추상 클래스, 인터페이스)를 참조하라는 원칙이다.


클래스, 인스턴스,객체는 무엇인가요?

  • 클래스 : 객체를 정의하는 틀, 설계도와 같은 의미로 사용됩니다.(메소드 영역에 저장)
  • 인스턴스 : 클래스를 이용해 생성된 객체를 인스턴스라 합니다. (힙 영역에 저장)
  • 객체 : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 의미합니다.


자바의 원시타입들은 무엇이 있으며 각각 몇 바이트를 차지하나요?

  • 정수형 byte : 1, short : 2, int : 4, long : 8
  • 실수형 float : 4, double : 8
  • 문자형 char : 2
  • 논리형 boolean : 1


컬렉션 프레임워크에 대해서 설명해주세요.

  • 널리 알려져 있는 자료구조를 바탕으로 객체, 데이터들을 효율적으로 관리할 수 있는 자료구조들이 있는 라이브러리를 말합니다.
  • List : 입력의 순서 유지, 중복 허용, 인덱스로 접근 가능
    • ArrayList : 단방향 포인터 구조 데이터, 조회가 빠름
    • LinkedList : 양방향 포인터 구조 데이터, 삽입 삭제가 빠름
  • Set : 입력 순서 유지 X, 중복 허용하지 않음, 인덱스 접근 X, iterator로 조회
    • HashSet : 순서 보장 X, 중복 허용 X
    • LinkedHashSet : 입력 순서를 보장, 종복 허용 X
    • TreeSet : 입력한 데이터의 크기가 비교 가능한 경우 오름차순으로 정렬, 중복 허용 X, 입력된 데이터가 사용자 정의 객체인 경우 Comparable 구현하여 정렬 기준 설정 가능
  • Map : key, Value 구조(key, value 모두 null 들어갈 수 있다.), Key는 순서 유지X, 중복 허용X / Value는 중복 허용, 인덱스 접근 X, iterator로 조회
    • HashMap : 순서 보장 X, 중복 key 허용 X
    • LinkedHashMap : Key에 대한 입력 순서 보장, 중복 Key 허용 X
    • TreeMap : 레드-블랙 트리 기반으로 Key, Value 저장, Key 데이터 크기가 비교 가능한 경우 오름차순으로 정렬, 중복 Key 허용 X, 입력된 데이터가 사용자 정의 객체인 경우 Comparable 구현하여 정렬 기준 설정 가능
      • 레드-블랙 트리 : 자가 균형 이진 탐색 트리의 일종이다.


Stream이란?

  • 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소입니다.
  • Stream의 경우 반복을 알아서 처리하고 결과값을 어딘가에 저장하는 내부반복을 사용합니다.
  • 덕분에 직접 반복문을 적을 필요가 없으며, 병렬성 처리에 이점이 있습니다.
    • 내부반복을 이용하기 때문에 스레드 공유자원에 대한 동기화를 관리해줄 필요가 없습니다.
  • 예시 : filter, distinct, map, reduce 등


제네릭에 대해서 설명해주세요.

  • 제너릭은 자바의 타입 안정성을 맡고 있습니다. 컴파일 과정에서 타입체크를 해주므로 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줍니다.


어노테이션에 대해서 설명해주세요.

  • 어노테이션은 인터페이스를 기반으로 한 문법으로 주석처럼 코드에 달아 클래스에 특별한 의미를 부여하거나 기능을 주입할 수 있습니다.


인터페이스와 추상클래스의 차이점에 대해 설명해주세요.

  • 인터페이스
    • 모든 메소드가 추상메소드로 이루어져 있는 것을 말합니다.
    • 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용합니다.
    • 다중 상속이 가능하고 인터페이스를 상속하는 집합 간에는 연관관계가 없습니다.
  • 추상클래스
    • 클래스 내 하나의 이상의 추상 메소드(abstract)를 포함한 경우를 말합니다.
    • 객체의 추상적인 상위 개념으로 공통된 개념을 표현할 때 사용합니다.
    • 단일 상속만 가능하고, 추상 클래스를 상속하는 집합 간에는 연관관계가 있습니다.


정적(static)이란 무엇인가요?

  • static은 클래스 멤버라고 합니다. JVM의 클래스 로더가 클래스를 로딩해서 Runtime Data Area의 메소드 영역에 저장할 때 클래스별로 관리됩니다.
  • static 키워드를 통해 생성된 정적멤버들은 Permanent Generation(자바7) 또는 Metaspace(자바8부터)에 저장되고 해당 메모리는 모든 객체가 공유하게 됩니다.
  • 하지만 GC 관리 밖에 존재하기 때문에 프로그램 종료까지 존재하게 됩니다. 남발하게 되면 시스템 성능에 문제가 될 수 있습니다.


접근 제어자의 종류와 이에 대해 설명해주세요.

  • private : 해당 클래스 내에서만 접근 가능
  • default : 같은 패키지 내에서만 접근 가능
  • protected : 상속한 클래스까지 접근 가능, 다른 패키지여도 자식 클래스면 접근 가능하다.
  • public : 전체 영역에서 접근 가능


final이 클래스, 메소드, 변수에 붙었을 때 차이를 알고 있나요?

  • final + 클래스 : 상속이 불가하다.
  • final + 메소드 : 오버라이딩이 불가하다.
  • final + 변수 : 상수화되어 수정이 불가하다.


Java8에서 추가된 기능에 대해서 설명해주세요.

  • Java8부터 Lambda식, Stream API, Optional, 날짜 시간 API, StringJoiner 등이 추가되었습니다. 또한 Permanent Generation이 사라지고 Metaspace 영역(Native 메모리 영역에 속함)이 생겼습니다.
    • Permanent Generation은 Class, Method Code가 저장되는 영역이며 힙 영역에 속했다.
    • Classloader가 현재까지 로드한 Class의 Metadata가 저장되는 공간이며 Native 메모리 영역에 속한다. 또한 크기 제한이 없다.
      • Metadata : 데이터에 대한 데이터를 의미한다. 다른 데이터를 설명하기 위한 데이터를 말하고 구조화된 정보를 분석, 분류하고 정보를 추가하기 위해 그 데이터에 뒤를 따라 가는 정보를 말한다.

Java11에서 추가된 기능에 대해서 설명해주세요.

  • Java11부터 String 클래스의 메소드, 컬렉션 인터페이스에서 toArray() 메소드를 오버로딩하는 메소드, javac 컴파일 없이 바로 실행 가능, GC 버전 G1 GC로 변경되었습니다.


동일성(identity)와 동등성(equality)에 대해 설명해주세요. (equals(), ==)

  • 동일성은 참조하는 객체가 같은 것을 의미하고 동등성은 객체의 값이 같은 것을 의미합니다.
  • 기본적으로 equals()는 동일성 비교를 합니다. 따라서 원한다면 메소드를 오버라이딩해서 동등성을 판단할 때 사용하면 됩니다.


원시타입과 참조타입의 차이에 대해 설명해주세요.

  • 원시타입은 정수, 실수, 논리를 직접 저장하는 8개의 타입을 말한다. 변수마다 사용할 수 있는 값의 범위가 있고 기본값이 존재한다. 원시타입은 스택에 저장이 된다.
    • 범위를 넘어가면 오버플로우 발생
  • 참조타입은 원시타입을 제외한 모두를 일컫는다. 번지를 통해 객체를 참조한다는 뜻이다. Object 클래스를 상속하거나, Object 클래스입니다. 참조 타입은 힙 영역에 저장이 된다.


Checked Exception과 Unchecked Exception에 대해 설명해주세요. 스프링 트랜잭션 추상화에서 rollback 대상은 무엇일까요?

  • 둘의 차이는 RuntimeException을 상속하는가의 여부에 따라 다릅니다. RuntimeException을 상속하면 UncheckedException입니다.
  • 스프링 트랜잭션 추상화 rollback 대상은 UncheckedException입니다.
  • CheckedException은 컴파일 실행이 안되기 때문에 예외 처리를 꼭 해줘야 한다.


자바에서 null을 안전하게 다루는 방법에 대해 설명해주세요.

  • Spring Assert를 이용해 null 방어하는 방법
  • 자바8부터 추가된 Optional 객체로 감싸는 방법
  • 롬복의 @NonNull을 사용하는 방법
  • 엔티티 필드를 검증하기 위해 @NotNull을 사용하는 방법
    • @Column(nullable = false)은 JPA가 만든 엔티티 필드 값이 Null로 채워져서 정상적으로 처리되다가 DB에 도착한 순간 NOT NULL 옵션이 발생하여 예외처리가 된다.
    • @NotNull은 필드값이 Null로 채워지는 순간 예외가 처리된다. @NotNull이 더 빠른 단계에서 예외를 검출한다.
    • @NotNull vs @Column(nullable = false)_현구막
  • 예외 처리를 다른 곳에서 한다면 @NotNull(message=”~~”) 를 이용하여 null값이 오면 메세지로 리턴해주는 방법


String, StringBuilder, StringBuffer 각각의 차이에 대해 설명해주세요.

  • String은 불변입니다. 그래서 StringBuilder, StringBuffer를 사용하는 가변 타입입니다.
  • StringBuilder는 Thread-safe하지 않습니다. 따라서 멀티 스레드 환경일 때는 StringBuffer를 사용합니다.


강한 결합과 느슨한 결합이 무엇인지 설명해주세요.

  • 결합도는 의존성의 정도를 나타냅니다. 다른 모듈에 대해 얼마나 많은 정보를 알고 있는지에 대한 척도입니다.
  • 어떤 모듈이 다른 모듈에 대해 필요한 정보(인터페이스로 추상화된 고수준의 정책)만 알고 있다면 두 모듈은 낮은 결합도를 가진다고 합니다.
  • 객체지향 관점에서 결합도는 객체 또는 클래스가 협력에 필요한 적절한 수준의 관계를 유지하고 있는지를 나타냅니다. 그러므로 강한 결합도는 지양해야 하고 적절한 결합도를 유지할 수 있도록 고민하고 설계해야 합니다.


Mutable 객체와 Immutable 객체의 차이점에 대해 설명해주세요.

  • Mutable 객체는 가변 객체입니다. class의 인스턴스가 생성된 이후 내부 상태가 변경 가능한 객체입니다.
    • 멀티 스레드 환경에서 사용하려면 별도의 동기화 처리가 필요합니다.
    • 대표적으로 ArrayList, HashMap, StringBuilder, StringBuffer(멀티스레드 환경에서 사용) 등이 있습니다.
    • 이 외에도 개발자가 커스텀한 객체가 내부 상태가 변화가 가능하다면 그것도 가변 객체이다.
  • Immutable 객체는 불변 객체입니다. class의 인스턴스가 생성된 이후 내부 상태를 변경할 수 없는 객체입니다.
    • 멀티 스레드 환경에서 안전하게 사용할 수 있다는 신뢰성이 보장됩니다.
    • 대표적인 불변 객체는 String이 있습니다.
    • 이 외에도 개발자가 커스텀 객체를 내부 상태가 변하지 않게 만든다면 그것도 불변 객체이다.


직렬화와 역직렬화에 대해서 설명해주세요.

  • 직렬화란 자바 시스템 내부에서 사용되는 객체나 데이터를 외부의 자바 시스템에서도 사용할 수 있게 바이트 형태로 데이터를 변환하는 기술입니다.
    • JVM의 메모리에서만 상주되어 있는 객체 데이터를 영속화가 필요할 때 사용됩니다. 시스템이 종료되어도 저장되는 장점이 있고 영속화된 데이터이므로 네트워크 전송이 가능합니다.
  • 역직렬화는 바이트로 변환된 데이터를 다시 자바 오브젝트 또는 데이터로 변환하는 기술입니다.
    • JVM의 힙, 스택 메모리에 상주한 객체 데이터를 직렬화를 통해 바이트 형태로 변환하여 DB나 파일 외부 저장소에 저장한다. 그리고 다른 컴퓨터에서 이 파일을 가져와 역직렬화를 통해 자바 객체로 변환하여 JVM 메모리에 적재한다.

스크린샷 2023-11-16 오후 12 19 13


자바의 동시성 이슈(공유자원 접근)에 대해 설명해주세요.

  • 동시성 문제란 동일한 자원에 대해 여러 스레드가 동시에 접근하면서 발생하는 문제입니다.
  • 동시성 문제가 발생하는 곳은 인스턴스 필드 (주로 싱글톤) 또는 static 같은 공용 필드에 접근할 때 발생합니다.
  • 무조건 동시에 접근한다고 문제가 발생하는 것이 아니라 값을 변경할 때 문제가 생기며 읽기만 한다면 동시성 문제는 발생하지 않습니다.

해결책

  • ThreadLocal : 해당 스레드만 접근할 수 있는 개인 저장소
private ThreadLocal<String> threadStore = new ThreadLocal<>();
threadStore.set("hi"); //값 저장
threadStore.get(); //값 조회
threadStore.remove(); //값 제거
  • 반드시 스레드를 사용하고 나서 값들을 제거해줘야 한다.
    • A 스레드 값 저장, 값 조회, 값 제거 > B 스레드 값 저장, 값 조회, 값 제거


  • syncronized : 기본 syncronized 키워드를 사용해서 여러 쓰레드가 동시에 해당 접근할 수 없도록 한다.
    • synchronized 가 선언된 블럭에는 동시에 하나의 스레드만 접근할 수 있다.
    • 해당 synchronized 를 남용하면 lock이 걸리는 쓰레드가 많아져 성능상 이슈가 발생할 수 있습니다.


추가적인 문제 상황

  • 동시성 프로그램에서는 CPU와 RAM 중간에 위치한 CPU Cache Memory와 병렬성이라는 특징 때문에 가시성 문제, 원자성 문제가 발생할 수 있습니다.
  • 가시성 문제 : 여러 개의 스레드가 사용됨에 따라 CPU Cache Memory와 RAM의 데이터가 서로 일치하지 않아 생기는 문제입니다.
    • 하지만 여러 스레드가 공유 자원에 쓰기 연산을 할 경우 가시성을 보장했다고 해서 동시성을 보장하지는 않습니다.
  • 해결책 : 가시성을 보장해야 하는 변수에 volatile 키워드를 붇여줘서 RAM에서 바로 읽도록 해야 합니다.

  • 원자성 문제 : 여러 스레드가 공유자원에 동시에 쓰기 연산을 할 경우 잘못된 결과를 반환하는 것을 의미합니다.
    • 한줄의 프로그램 statement(문장)가 컴파일러에 의해 기계어로 변경되면서, 이를 기계가 순차적으로 처리하기 위한 여러 개의 machine instruction이 만들어져 실행되기 때문에 일어나는 현상을 설명하는 용어.
      • i++ > 기존 변수 읽고(READ), 연산하고(MODIFY), 저장한다(WRITE) > 여러 스레드가 해당 로직을 처리하면서 꼬이는 문제
  • 해결책 : synchronized, atomic 을 통해 원자성을 보장해야 합니다.


추가 학습할 것들


Reference: