동시성 테스트 코드 #48
Replies: 4 comments
-
1. CountDownLatchint count = 3;
CountDownLatch latch = new CountDownLatch(count);
latch.countDown(); // count를 -1 감소시킴.
latch.await(); // count가 0이 될때까지 대기.
2. CyclicBarrierint count = 3;
CyclicBarrier barrier = new CyclicBarrier(count, () -> {
// count만큼 await()가 호출되었을 때, 수행할 작업을 정의
});
barrier.await(); // count만큼 await()가 호출 될 때까지 대기.
|
Beta Was this translation helpful? Give feedback.
-
|
저는 동시성에 대해 테스트 코드를 작성 할때의 핵심은 “진짜 동시에 일어난 상황을 만들수 있는가”라고 생각합니다. CountDownLatch는 일회용입니다. 카운터가 0이 되면 대기 중이던 스레드들이 한꺼번에 풀려나고 재사용은 안 됩니다. 단발성(동시 출발 + 결과 집계) 시나리오(대부분의 동시성 테스트)에 자연스럽고, 카운트다운하는 쪽과 대기하는 쪽이 달라도 되어 유연합니다. CyclicBarrier는 재사용이 가능합니다. 그래서 일반적으로 기본은 CountDownLatch, 반복,단계가 중요할 때만 CyclicBarrier를 사용합니다. 다만 둘 다 "동시"를 만드는 메커니즘일 뿐, 동시성 테스트 자체의 진짜 어려움은 따로 있습니다. |
Beta Was this translation helpful? Give feedback.
-
|
동시성 테스트를 작성할 때는, 한 리소스에 대한 동시성 충돌 상황을 얼마나 의도한 대로 재현될 수 있을까가 제일 중요한 기준이라고 생각합니다. CountDownLatch와 CyclicBarrier 모두 여러 스레드의 실행 흐름을 제어할 때 사용할 수 있기에, 동시성 테스트에 활용할 수 있습니다. 1. CountDownLatchCountDownLatch는 특정 시점까지 스레드를 대기시키고 싶을 때 사용할 수 있는 동기화 도구입니다. 즉, 동시성 테스트에서 CountDownLatch를 사용하면 작업 스레드들이 실행될 때까지 메인 스레드를 대기시킬 수 있습니다. CountDownLatch locked = new CountDownLatch(1);
CountDownLatch release = new CountDownLatch(1);저는 테스트에서 첫번째 실행스레드가 For Update로 락을 잡기 이전에, 두번째 스레드가 로직을 실행하는 것을 막기 위해, 첫번째 스레드가 락을 획득했음을 표현하는 locked 카운트를 사용하여 스레드들의 실행 순서를 제어했습니다. 또한 모든 트랜잭션의 작업이 끝난 이후, release를 이용하여 락을 해제하는 시점을 표현했습니다. 즉, 실제로 락이 걸리는 정확한 시점을 테스트에서 알 수 없고, 락이 지속되는 기간도 제어하기 어렵기 때문에, CountDownLatch로 스레드 실행 시점을 제어하여 타이밍을 고정하는 방식으로 활용하였습니다. 2. CyclicBarrierCyclicBarrier는 여러 스레드가 같은 지점에 모두 도착할 때까지 기다렸다가 한번에 다음 단계로 넘어가게 하는 동기화 도구입니다. 즉, 여러 스레드를 동시에 실행시키고 싶을 때(즉, 대기 시켰다가 한번에 시작하는 것) 사용할 수 있습니다. 이번 미션에서는 동시에 모든 스레드가 실행되야할 상황이 나오지 않아 사용하지 않았는데요, 만약 "같은 예약을 여러 사용자가 동시에 취소하는 상황"과 같은 경우 사용할 수 있을 것 같습니다. 비교두가지 키워드를 언제 사용해야할지 비교해보았는데요, 실제로 제가 사용했던 경우처럼 1번 스레드가 락을 잡고 -> 2번 스레드가 실행되야하고 -> 1번 스레드가 락을 해제해야하는 실행 흐름을 순서대로 표현하고 싶은 경우에는 CountDownLatch이 더 자연스럽다고 생각했습니다. 테스트에서 중요한 것은 의도한 충돌 상황이 명확히 표현되는 것이라고 생각합니다. 따라서 동시에 시작된 스레드만 표현한다면 어떤 순서로 컨텍스트 스위칭이 일어나는지 알 수 없기 때문에, 저는 의도된 순서를 표현할 수 있는 CountDownLatch를 사용하였습니다. |
Beta Was this translation helpful? Give feedback.
-
|
동시성 테스트를 작성할 때 가장 중요한 점은 "여러 스레드가 정말 동시에 같은 충돌 지점에 접근하도록 할 수 있는가?"라고 생각합니다. 단순히 스레드를 여러개 띄워 요청을 보내는 코드에서는 동시성 문제가 발생하지 못할 수 도 있습니다. 그래서 테스트에서는 시작 시점을 통일하고, 모든 작업이 끝날 때 까지 기다린 뒤, 결과가 기대한 값인지 검증하는 구조가 궁금합니다. 1. CountDownLatch
해당 방식의 장점은 구조가 단순하고 직관적이라는 점입니다. 위에서 설명했듯 준비됐으면 기다리고( 하지만 일회성이라는 단점이 있습니다. 한번 count가 0이되면 재사용할 수 없고, 여러 단계가 있는 복잡한 테스트에는 적합하지 않다고합니다. 단계 많을 경우2. CyclicBarrier
장점은 모든 스레드가 같은 준비상태에 올라왔음을 명확히 보장할 수 있다는 점입니다.(추가로 테스트 대상 로직 바로 직전에 barrier을 두면 더 명확하게 경쟁 상황을 구현할 수 있다고 합니다.) 또한 반복적인 동시성 상황을 테스트하기 좋습니다. 단계 많을 경우 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
동시성에 대해서 테스트 코드를 통해 작성할 때,
저는 이번에
CountDownLatch,CyclicBarrier방식을 알게 되었습니다.동시성에 대해 테스트 코드를 작성해야할 때, 어떤 부분이 중요할 지에 초점을 맞춰 각각의 장단점을 서술해주세요
Beta Was this translation helpful? Give feedback.
All reactions