Coding 공부/Java

[Java_Summary] Singleton(synchronized), 상속, enum

CBJH 2024. 2. 13.
728x90
반응형

1. Singleton 복습 및 synchronized

 

synchronized 키워드는 멀티스레드 환경에서 메소드가 한 번에 하나의 스레드에 의해서만 실행될 수 있도록 보장합니다. 즉, 한 스레드가 getInstance() 메소드를 실행하고 있는 동안 다른 스레드는 해당 메소드의 실행이 완료될 때까지 대기해야 합니다. 이는 동시성 문제를 방지하는 데 필요하며, 특히 싱글턴 패턴의 인스턴스 생성과 같이 상태를 변경하는 연산에서 중요합니다.

싱글턴 패턴에서 synchronized 키워드를 사용하면, 여러 스레드가 동시에 getInstance() 메소드에 접근할 때 인스턴스가 중복으로 생성되는 것을 방지할 수 있습니다. 첫 번째 스레드가 인스턴스를 생성하고 있는 동안 다른 스레드는 대기하게 되고, 첫 번째 스레드가 인스턴스 생성을 완료하고 메소드를 빠져나가면, 대기하고 있던 스레드 중 하나가 메소드 실행을 시작할 수 있습니다. 그 시점에서는 이미 인스턴스가 생성되어 있기 때문에 새로운 인스턴스를 생성하지 않고 기존 인스턴스를 반환합니다.

그러나 synchronized를 메소드 레벨에서 사용하는 것은 성능상의 단점이 있습니다. 메소드 전체가 락(lock)의 범위가 되므로, 해당 메소드를 호출할 때마다 성능 저하가 발생할 수 있습니다. 특히 싱글턴 인스턴스가 이미 생성된 이후에는 추가적인 동기화 처리가 불필요하게 됩니다. 따라서 싱글턴 패턴에서는 다음과 같은 방법을 고려할 수 있습니다:

  • Double-checked locking (이중 검사 잠금): getInstance() 메소드 내에서 인스턴스가 null인지 먼저 검사하고, null인 경우에만 동기화 블록을 실행합니다. 이미 인스턴스가 생성되어 있는 경우에는 동기화 블록을 거치지 않으므로 성능이 향상됩니다.
  • Initialization-on-demand holder idiom (수요에 의한 초기화 홀더 관용구): 클래스 로더의 클래스 초기화 과정이 기본적으로 동기화를 보장하는 점을 이용하여 인스턴스 생성을 지연시키는 방법입니다. 이 방법은 성능 저하 없이 스레드 안전을 보장합니다.

synchronized 키워드를 사용한 동기화는 필요할 때 적절히 사용해야 하며, 특히 고성능이 요구되는 애플리케이션에서는 성능 저하를 초래할 수 있는 점을 고려해야 합니다.

 
 
Singleton 인스턴스 생성을 위한 예제
4번째 줄, 13번째 줄은 연습을 위한 예제이고 실무에서 사용하면 성능저하를 일으키므로 23번째 줄 처럼 코드를 작성한다.

 

   1.1 싱글톤 객체 생성 예제

  • 싱글톤은 static final에서 한 번만 생성되므로 객체를 100만개 생성해도 모두 똑같은 객체 레퍼런스를 가진다.

 

2. enum 키워드

 

자바에서 enum(열거형)은 서로 관련된 상수들의 집합을 정의할 때 사용하는 특별한 클래스 타입입니다. enum을 사용하면 코드의 가독성과 안정성이 향상됩니다. 가독성 면에서는 정수나 문자열 상수를 사용하는 것보다 enum을 사용하면 더 명확하게 의도를 표현할 수 있습니다. 안정성 면에서는 enum이 제공하는 타입 안전성으로 인해 유효하지 않은 값이 할당되는 것을 컴파일 시점에 방지할 수 있습니다.

enum의 특징:

  • 타입 안전성: enum은 정의된 상수 값만을 가질 수 있으므로, 유효하지 않은 값이 할당되는 것을 컴파일 시점에서 방지할 수 있습니다.
  • 자체적인 네임스페이스: enum의 각 열거형 상수는 enum 타입의 이름을 통해 접근됩니다. 이로 인해 이름 충돌을 방지할 수 있습니다.
  • 메소드 및 필드 추가 가능: enum은 단순한 상수 집합 이상의 기능을 제공합니다. enum 내에 메소드나 필드를 추가할 수 있고, 각 상수에 특정 값을 연결할 수도 있습니다.

 

   2.1 enum 예제

enum 자료형 또한 class처럼 필드와 메소드를 가질 수 있다.
class처럼 따로 new를 사용해서 인스턴스를 생성할 필요없이 static처럼 바로 사용할 수 있다.
enum명.상수명.멤버변수명 or enum명.상수명.메소드명으로 접근하여 값을 바꾸거나 메소드를 사용할 수 있다.
아직 잘 사용은 못하겠지만 class가 확장된 개념같다. 

 

3. 상속

  • extends로 부모 클래스를 받아오며 모든 기능을 사용할 수 있다.
  • 단, private 멤버 변수나 메소드는 사용할 수 없다. protected, default, public은 사용가능하다.
  • 중복적으로 새로 구현해야 되는 것을 줄여주고 생산성을 높여준다.
  • 부모 클래스 : 슈퍼 클래스(super class)
  • 자식 클래스 : 서브 클래스(sub class)
  • 자바에선 파이썬처럼 다중 상속을 지원하진 않으나 완전히 구현을 못하는 것은 아니다.

부모 클래스를 상속 받을 때 Heap영역에 생성되는 메모리 영역

 

   3.1 상속 예제

  • 자바는 상속 횟수에 제한을 두지 않는다. 
  • 상속받은 클래스의 객체 인스턴스를 생성하면 부모 영역까지 Heap에 메모리가 할당되어 모든 기능을 사용할 수 있다.

 

   3.2 상속 예제2

 

  • 오버라이딩 기능을 사용하여 부모 클래스에 있는 메서드명과 같은 메서드를 자식 클래스에 재정의할 수 있다. (주의: 매개변수의 개수가 다르면 오버라이딩이 아니게된다.)

   3.3 상속 예제3

  • 부모 클래스의 메서드를 super를 사용해서 불러올 수 있다. (주의: 소괄호는 사용하지 않는다)

 

   3.4 상속 예제4

  • 부모의 생성자 또한 super()를 사용해서 호출할 수 있다. this()와 비슷한 개념이다.
  • 기본적으로 super();가 생략되어진 상태로 자식 클래스에서 생성자로 객체 인스턴스가 생성되면 부모 클래스 생성자부터 생성된다. 따라서 자식클래스에서 super();로 생성자 호출을 하고 싶으면 생성자의 첫번째 줄에서 호출한다. 두번째 줄에서 호출하면 오류가 뜬다.

 

 

 

댓글