본문 바로가기

안드로이드/알아두기

[안드로이드] 동기화에 대하여 알아보자(2) - Synchronize, @Volatile

어제에 이어서 오늘은 이론적인 내용도 좋지만 실질적으로 프로그래밍 되는 방법을 몇 개 정리해보려고 한다.

 

@Volatile

먼저 볼 것은  어노테이션의 한 종류인 Volatile이다. 이 어노테이션은 상수가 아닌 변수에만 사용 가능한 것으로서, 이게 붙으면 해당 변수는 캐시 메모리가 아닌 메인 메모리에서 직접 읽고/쓰기를 진행해야 하는 변수로 선언이 되는 것이다.

 

이런 어노테이션이 나온 이유는 singleton pattern에서 동기화 문제가 발생하기 때문이다. 만약 서로 다른 2개의 CPU에서 Singleton Pattern이며, 초기화 되어 있지 않은 특정 클래스의 Instance에 접근한다고 가정해보자.  해당 instance에 동시에 2개의 CPU가 동시에 접근을 할 것이며, 해당 instance를 읽을 당시 두 CPU에는 instance가 초기화 되어 있지 않기 때문에 먼저 읽은 CPU가 instance를 초기화 시키더라도, 초기화 직후 다른 CPU가 instance를 또 다시 초기화 시킬 수 있는 것이다. 이러한 문제는 캐시가 서로 다르고 동시에 작업을 하면서 2개의 CPU간의 캐시 싱크가 맞지 않아 발생하는 문제이다. 따라서 Volatile 어노테이션을 붙여서 캐시의 싱크가 맞지 않는 것을 메모리에 직접 접근하여 해결하는 것이다. 다만 캐시 메모리가 아닌 메인 메모리에 직접 접근해서 작업을 하게 되면 시간이 걸려서 자원 소모가 심하다는 단점이 발생한다. 이 외 더 자세한 내용은 공식 문서를 참고하길 바란다.

 

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-volatile/

 

Volatile - Kotlin Programming Language

 

kotlinlang.org

 

Synchronize

Synchronize는 간단하게 설명하면 단일 스레드만 해당 코드 블럭에 접근할 수 있게 해주는 것이다. 좀 더 장황하게 설명하면, 멀티 스레드 환경에서 해당 메소드가 실행될 때, 여러 스레드에 의해서 동시에 실행되는 것을 막고 오직 단일 스레드만이 해당 메소드가 실행되게 해준다고 할 수 있다. 더 자세한 내용은 공식 문서를 참고하길 바란다.

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-synchronized/

 

Synchronized - Kotlin Programming Language

 

kotlinlang.org

 

@Volatile과 Synchronize 사용 예시

class HelperClass {
    companion object {
        @Volatile
        private var instance: HelperClass? = null

        fun getInstance() =
            instance ?: synchronized(HelperClass::class.java) {
                instance ?: HelperClass().also {
                    instance = it
                }
            }
    }
}