JAVA

람다 표현식을 사용한 잠금(lock) 관리

.노을. 2017. 3. 17. 18:52
반응형

잠금(lock)은 병렬로 실행되는 자바 애플리케이션에서 중요한 역할 을 한다. 

synchronized 는 상호 배재(mutual exclusion)를 제공하기 위해 사용되어온 오래된 키워드이지만, 두가지 단점을 가지고 있다. 

  1. 메서드가 호출되는 시간을 제어하기 어렵다. - 이것은 데드록(deadlock) 과 라이브록(livelock) 이 발생할 가능성을 증가시킨다.
  2. synchronized 를 실제 적용하는 것이 어렵다. - 코드가 thread safety에 있는지를 체크하기 위한 unit test를 어렵게 만든다. 

synchronized 의 문제를 해결하기 위해 자바5 에서 Lock 인터페이스와 ReentrantLock 등의 구현이 추가 되었다. Lock 인터페이스는 lock, unlock, check 등에 대한 더 향상된 인터페이스를 제공하며 특정 시간 안에 잠금(Lock)을 얻지 못하면 타임 아웃되도록 한다.

[Lock 인터페이스를 사용한 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Locking {
    Lock lock = new ReentrantLock(); // or mock
 
    protected void setLock(final Lock mock) {
        lock = mock;
    }
 
    public void doOp1() {
        lock.lock();
        try {
            // .. critical code ..
        } finally {
            lock.unlock();
        }
    }
 
    // ...
 
}
cs


Lock 을 상요한 doOp2() 를 추가해야 한다면, lock을 설정하지 않거나, 해지하지 않는 등의 오류가 쉽게 발생 할 수 있으며 유지 보수도 어렵다.

[람다 표현식을 사용한 코드]

1
2
3
4
5
6
7
8
9
10
public class Locker {
    public static void runLocked(Lock lock, Runnable block) {
        lock.lock();
        try {
            block.run();
        } finally {
            lock.unlock();
        }
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Locking {
    Lock lock = new ReentrantLock(); // or mock
 
    protected void setLock(final Lock mock) {
        lock = mock;
    }
 
    public void doOp1() {
        runLocked(lock, () -> { /* ... critical code ... */});
    }
 
    public void doOp2() {
        runLocked(lock, () -> { /* ... critical code ... */});
    }
 
    public void doOp3() {
        runLocked(lock, () -> { /* ... critical code ... */});
    }
 
    // ...
 
}
cs

위의 코드처럼 람다를 사용할 경우 매우 쉽고 간결하게 문제를 해결할 수 있다.


반응형