개인 토이 프로젝트를 할 때에 싱글톤을 자주 활용했었다. 하지만 내가 사용하고 많은 인터넷 예제들이 사용하던 싱글톤을 만드는 방법이 Multi Thread 환경에서 위험하다는 것은 아주 유명한 이야기이다.
토이 프로젝트를 할 때에는 어차피 모든 싱글톤 객체를 UI Thread 위에서 만들고 있었다. 따라서 사실상 Thread 관리를 해야한다는 필요성을 느끼지 못했다. 그러나 당시에도 테스트를 진행해 볼 때 싱글턴 객체가 하나가 아닌 적이 발생하여 불편함이 있었고.. 이번 기회에 조사해보기로 마음먹었다.
constructor가 private인 클래스에서 static 변수로 된 단 하나의 인스턴스를 getInstance()를 사용하여 받아오는 방법이다.
최초부터 static 변수에 인스턴스를 만들어두고 사용하는 상대적으로 안전한 방법이 있지만, 그렇게 하면 사용하지 않더라도 메모리가 할당된다는 단점이 있다고 한다.
synchronized를 사용하면 멀티스레드에서도 같은 객체를 가져올 것을 보장할 수 있지만, 원리상 여러 개의 스레드들이 줄을 서서 다른 스레드가 해당 함수를 다 돌고 나가기를 기다려야 하는 단점이 있다고 한다. 따라서 함수 자체를 synchronized로 설정하기보다, null체크를 한번하고 그 후에 synchronized로 한번 더 체크한 후 반환하는 것으로 개선한 것이다.
이때에 Voletile이라는 것에 대해 배웠는데, cpu 캐시에 생기는 임시 데이터를 생성하지 않아서 속도는 조금 느리지만 같은 변수일 것을 더욱 보장할 수 있는 기능이라고 한다.
Joshua Bloch가 언급한 이디엄으로, 클래스 대신 enum으로 정의하는 것이다. 그러나 안드로이드에서는 context라는 의존성이 필요한 경우가 많기 때문에 많은 상황에서의 사용에 제한이 걸릴 가능성이 높다고 한다.
별개의 static class와 그 안의 static 변수로 인스턴스를 가지고 있어서, getInstance()를 불렀을 때가 되어서야 static 변수에 인스턴스가 생기면서 단 하나를 보장할 수 있는 방법이라고 한다.
단 하나의 인스턴스만 필요한 경우 클래스를 만들지 말고 바로 인스턴스를 만들어서 사용하는 방법이다. 그러나 클래스로더가 여러 개 있을 경우에는 클래스가 여러번 로드되면서 싱글톤이 아니게 될 수도 있다고 한다.
Dagger의 singleton이 안전하듯이 hilt를 사용하여 싱글턴 객체를 관리한다면, Thread에서 안전할 것을 보장할 수 있다고 한다.
만약에 Hilt를 적용한다면 문제 없을 것이고, Hilt를 적용하지 않는다면, LazyHolder 패턴을 사용하여 만들면 좋을 것 같다.
https://jainilgada.medium.com/thread-safe-singleton-pattern-b429e79825d2
https://rockdrumy.tistory.com/1412
https://stackoverflow.com/questions/30179793/are-kotlins-singletons-thread-safe
https://stackoverflow.com/questions/56825097/synchronized-singleton-in-kotlin
https://kotlinlang.org/docs/object-declarations.html
https://stackoverflow.com/questions/30240338/is-singleton-in-dagger-2-thread-safe
https://developer.android.com/training/dependency-injection/manual?hl=ko
https://injae-kim.github.io/dev/2020/08/06/singleton-pattern-usage.html
https://sogno-ing.tistory.com/102
https://coding-start.tistory.com/203