2. 멀티 쓰레드 환경에서 안전하게 구현하는 방법
방법 : Double checked locking, Inner Class
멀티 스레드 환경에서는 이 방법은 thread safe하지 않는다고 한다.
만약 2개의 쓰레드가 존재할 때, 1번 스레드가 if문 안으로 접근하게 된다면 아직 인스턴스를 생성하지 않은 시점에서 2번 스레드도 if문 안으로 진입하게 되는 상황이 있다고 하자.
1, 2번이 가지게되는 인스턴스가 달라지게 된다.
가장 쉬운 방법 중 하나는 메서드를 동기화 시키는 것이다. synchronized키워드를 사용한다.
적용된 메서드에서 한번에 딱 하나의 스레드만 들어오게끔 만드는, 동시에 여러 쓰레드가 이 메서드 안으로 들어올 수 없기 때문에, 멀티 스레드 환경에서 하나의 인스턴스만 보장할 수 있다.
단점 :
getInstance()를 호출할 때마다 동기화 처리하는 작업 때문에 성능 이슈가 생길 수 있다.
만약 synchronized를 사용하지 않으려면 미리 static final로 인스턴스를 생성한다.
이른 초기화(Eager Initialization) 사용
private static final Settings INSTACE = new Settings();이 클래스는 애플리케이션이 로딩되는 시점에 satic 필드들이 초기화 된다.
이 방법은 thread safe하다.
단점 : 미리 만든다는 자체가 단점이 될 수 있다.
인스턴스를 만드는 과정이 길고 비용이 많이 발생한다면, 만들어놨는데 사용하질 않아?? 그럼 애플리케이션 로딩할 때 많은 리소스를 사용했음에도 불구하고 안쓰는 객체를 생성한 것이다.
그럼 어떤 방법이 있을까?
Double checked locking 사용하기 —> 체크를 두번하기
그럼 나는 인스턴스를 나중에 사용이 될 때 만들고 싶은데 synchronized 블럭의 비용이 신경이 쓰이는데…. 어떻게하면 좋겠는가…?
먼저, if문으로 체크 하고나서, 분기 안으로 들어오면 synchronized블럭을 생성해서 Setting 클래스를 lock으로 사용하고, 그 안에서 한번 더 검사를 진행하고 인스턴스를 생성한다.
volatile 키워드 사용
장점 : 메소드 레벨에서
synchronized가 있는것에 비하면 성능에 유리하다.단점 : 매우 복잡한 방법, 왜 volaatile을 쓰는지 이해해야 하고, java 1.5이상 부터 동작한다.
좀 더 심플하게 만드는 법 - inner 클래스 사용 : 권장하는 방법 중 하나
getInstance()를 통해서 inner class에서 생성한 인스턴스를 리턴하게 됨
이 방법은 멀티 스레드 환경에서도 안전하고, getInstance()가 호출될 때 SettingsHolder 클래스가 로딩이 되고, 그 때 Settings 인스턴스를 생성하기 때문에 Lazy Loading이 가능한 코드가 된다.
Last updated