Synchronized와 ReentrantLock의 차이

Picbel·2022년 7월 31일
1

Concurrency Programming

목록 보기
2/4
post-thumbnail

Jvm환경에서 쓰레드에 Lock걸어야 할때 여러가지 방법이 있습니다
그중 오늘은 Synchronized와 ReentrantLock의 차이점에 대해 기술합니다

Synchronized

Synchronized는 method와 statements 두가지로 구분 할수있습니다.
먼저 method를 확인하여보겠습니다.

@Synchronized
fun syncMethod() = run { }

@Synchronized
fun syncMethod2() = run { }

syncMethod()를 보면 @Synchronized 어노테이션으로 method 전체에 lock걸었습니다.
다음과 같은 방법으로 lock을 걸면 해당 method는 한번에 하나의 스레드에서만 실행된다.
주의 해야할것은 Synchronized를 method에 걸면 같은 클래스의 다른 Synchronized method와 같은 진입조건을 가지게 됩니다.
즉 syncMethod2()라는 method가있고 @Synchronized로 lock을 주었다면
syncMethod()가 실행되는 동안 syncMethod2()는 다른 스레드에서 접근이 불가합니다.

다음은 statements로 Synchronized를 사용하는 법입니다.

fun syncStatements() {
	synchronized(this) {
    	doSomething()
    }
    doSomething2()
}

syncStatements()를 보시면 @Synchronized없이 synchronized(this)를 통해 lock을 걸었습니다.
문법에서 보듯이 synchronized영역을 해당 코드블럭 내로 한정짓는 역할을 해줍니다.
syncStatements()실행시 lock은 doSomething()에만 걸리고 doSomething2()는 여러 스레드에서 동시 접근이 가능해집니다.
method방식보다 좀 더 유연한 lock관리와 전략이 가능해집니다.
하지만 lock을 좀 더 다양하게 관리하거나 복잡한 상황을 컨트롤해야할 수도있습니다.
특정 시간을 기다리고 안되면 무시하고 지나가야한다던지 lock을 잡는 순서를 보장해야하는 경우가 있을수 있죠
그런경우에 사용하는것이 ReentrantLock입니다.

ReentrantLock

사용방법은 굉장히 간단합니다.

private val lock: ReentrantLock = ReentrantLock(true)

fun foo(){
	try {
    	lock.lock()
        doSomething()
    }finally {
    	lock.unlock()
    }
}

다음과 같이 ReentrantLock선언이후 해당 객체에 있는 메서드를 이용하여 lock을 잡으면됩니다.
추가로 lock을 열었으면 꼭 unlock을 해줘야합니다.
코틀린의 경우 withLock을 사용하면 굉장히 편리하게 사용할수 있습니다.

fun foo2(){
 	lock.withLock {
		doSomething()
	}
}


kotlin에서 편리한 사용을 위해 만들어진 확장함수가 있습니다.
한번 확인하여보세요(read,write도 있습니다.)

다시 ReentrantLock으로 돌아와서 ReentrantLock은 다양한 기능을 제공합니다.
자세한 기능은 해당 객체를 직접 열어서 확인해보는것을 권장합니다.
해당 포스팅에선 대표적인 몇가지 기능들을 소개할려합니다.

ReentrantLock을 생성할때 생성자에 Boolean값을 입력할수 있는데 이는 lock을 잡는 경쟁조건을 fair하게 할것인지 아닌지를 설정 할수있습니다.
fair와 unfair의 차이는 이 글에서 확인하여주세요. fair-and-unfair-lock

다음은 method를 확인하여 보겠습니다.

  • lock(): lock 획득합니다.
  • unlock(): lock을 해제합니다.
  • tryLock(): lock을 얻으려 시도합니다. 실패할경우 false를 리턴하고 성공할경우 true를 리턴합니다. 특정시간을 기다리고 획득할수도있습니다.
    주의 할점은 해당 ReentrantLock의 경쟁조건을 fair로 설정하여도 tryLock으로 lock획득을 시도할시 불공정하게 처리됩니다.
  • isHeldByCurrentThread(): 현재 스레드가 lock을 얻었는가?
  • nowCondition(): 해당 lock에서 사용할 Condition 인스턴스를 받습니다.

ReentrantLock에서 좀더 기능을 특수화 시킨 ReentrantReadWriteLock도 있습니다.
해당 lock은 이름에서 보듯 read와 write시 Lock전략을 다르게 잡는 lock입니다.
적은수의 write와 많은 read시 모두 lock을 잡으면 비효율적이기에 해당상황에는 ReentrantReadWriteLock을 사용하는것이 좋습니다.

정리하자면 다음과 같습니다.

간단 요약

Lock을 잡아야 하는데 간단하게 잡아야한다면 Synchronized
그 외 복잡한 상황과 직접 Thread나 fair모드 등 여러 상황을 설정해야한다면 ReentrantLock을 사용하면 됩니다.

profile
Software Developer

0개의 댓글