동시성 용어집

동시성 분야의 개념 31개를 한 장에 모았습니다. 갱신 손실 · 구조화된 동시성 · 낙관적 락 · 데드락 등 — 코드베이스에서 뽑아 뜻과 관계를 정리했습니다.

갱신 손실 (lost update)
두 요청이 같은 값을 읽고 각자 고쳐 쓰면 먼저 쓴 변경이 사라진다. 재고 · 잔액 · 쿠폰처럼 읽고-고치고-쓰는 흐름에서 생긴다
구조화된 동시성 (structured concurrency)
자식 작업의 수명이 그것을 연 스코프 안에 갇힌다는 원칙. 스코프는 자식이 모두 끝나야 끝나고, 하나가 실패하면 형제를 취소한다
낙관적 락 (optimistic locking, @Version)
잠그지 않고 읽은 뒤, 저장할 때 버전 컬럼이 그대로인지 비교한다. 다르면 예외를 내고 재시도한다. 충돌이 드문 갱신에 맞다
데드락 (deadlock, 교착 상태)
둘 이상의 실행 단위가 서로가 쥔 자원을 기다리며 영원히 멈춘 상태. 코프먼 네 조건이 모두 있을 때 생기고, 잠금 순서를 고정하면 순환 대기가 깨진다. DB 에서는 InnoDB 가 감지해 한쪽 트랜잭션을 롤백한다
동기화
여러 실행 단위가 같은 자원을 만질 때 순서와 배타를 보장한다. 잠금으로 막을지, 원자 연산으로 잠금 없이 갈지, 아예 공유하지 않을지 고른다
동시 갱신 제어
같은 행을 여러 요청이 동시에 고칠 때 한쪽 변경이 사라지지 않게 한다. 충돌이 드물면 낙관적 락, 잦거나 실패 비용이 크면 비관적 락, 단순 증감이면 조건부 원자 갱신을 고른다
동시성 (concurrency, 동시성 프로그래밍)
한 프로세스 안에서 여러 일을 겹쳐 진행하는 기법. 무엇으로 실행할지, 메모리를 어떻게 공유하고 지킬지, 기다림(IO)을 어떻게 다룰지를 차례로 정한다
락 경합 (lock contention)
여러 실행 단위가 같은 잠금을 잡으려 몰려 대부분이 기다리는 데 시간을 쓰는 상태. 코어를 늘려도 처리량이 오르지 않는다
레이스 컨디션 (race condition, 경쟁 상태, data race)
여러 실행 단위가 공유 자원을 동시에 읽고 쓰는 순서에 따라 결과가 달라지는 상태. 확인 후 실행(check-then-act)과 읽고-고치고-쓰기(read-modify-write)가 대표 모양이다
리액티브 스트림 (Reactive Streams, Reactor, Mono, Flux)
비동기 데이터 흐름을 Publisher·Subscriber·Subscription·Processor 로 잇고, 구독자가 request(n) 으로 받을 양을 알려 배압을 거는 논블로킹 표준. Reactor 의 Mono·Flux 가 구현이다
메모리 가시성 (memory visibility)
한 스레드가 쓴 값이 다른 스레드에 언제 보이는지의 문제. CPU 캐시·재배치 때문에 happens-before 관계가 없으면 보장되지 않는다
뮤텍스 (mutex, mutual exclusion, lock)
한 번에 하나만 임계 구역에 들어가게 하는 잠금. 잠근 쪽만 풀 수 있다. 여러 잠금을 순서 없이 잡으면 교착이 생긴다
분산락 (distributed lock)
여러 프로세스·노드가 공유 자원에 동시에 들어가지 않게 외부 저장소(Redis·ZooKeeper 등)에 잠금을 둔다. TTL 과 펜싱 토큰이 없으면 만료 뒤 두 쥔 자가 생긴다
블로킹 · 논블로킹 (blocking, non-blocking)
호출이 결과가 나올 때까지 실행 단위를 붙잡으면 블로킹, 곧바로 돌아오고 결과는 나중에 받으면 논블로킹이다. 호출한 쪽이 제어권을 돌려받느냐의 축이다
비관적 락 (pessimistic locking, PESSIMISTIC_WRITE)
읽는 시점에 행을 잠가(SELECT ... FOR UPDATE) 다른 트랜잭션의 수정을 커밋까지 막는다. 충돌이 잦거나 한 번의 실패가 비싼 차감에 맞다
비동기 처리
IO 를 기다리는 동안 실행 단위를 막지 않고 다른 일을 하게 한다. 결과를 콜백으로 받을지, 조합 가능한 Future 로 받을지, 순차 코드 모양(async/await)으로 받을지 고른다
세마포어 (semaphore, counting semaphore)
허가(permit) N 개를 두고 동시에 들어갈 수 있는 실행 단위 수를 N 으로 제한한다. 외부 API 동시 호출 상한처럼 자원 수를 맞출 때 쓴다
스레드 (thread, OS thread, 플랫폼 스레드, platform thread)
프로세스 안에서 독립적으로 실행되는 OS 스케줄링 단위. 메모리는 프로세스와 공유하고 스택은 따로 가진다. 하나당 스택 메모리와 컨텍스트 스위칭 비용이 든다
스레드 풀 (thread pool, executor, ThreadPoolExecutor, ExecutorService)
스레드를 미리 정해진 수만큼 만들어 두고 작업 큐에서 꺼내 재사용한다. 생성 비용을 없애고 동시 실행 수에 상한을 건다. ThreadPoolExecutor 의 core·max·keepAlive·큐·거절 정책이 동작을 정한다
실행 단위 구성
일을 무엇 위에서 돌릴지 정한다 — OS 스레드를 직접 쓸지, 풀로 재사용할지, 가상 스레드나 코루틴처럼 가벼운 단위를 얹을지
원자 연산 (atomic operation, AtomicLong, AtomicReference, atomic)
읽기·계산·쓰기를 중간에 끼어들 수 없는 한 동작으로 한다. 카운터 증가·참조 교체처럼 작은 공유 값은 잠금 없이 AtomicXxx 로 지킨다
이벤트 루프 블로킹 (blocking the event loop, BlockHound)
소수의 이벤트 루프 스레드에서 JDBC·파일 IO·Thread.sleep·block() 같은 블로킹 호출을 해 그 스레드가 맡은 모든 연결이 함께 멈추는 상태
임계 구역 (critical section)
공유 자원을 만지는 코드 구간. 동시에 하나(또는 정해진 수)만 들어가야 결과가 맞는다. 짧게 잡을수록 경합이 준다
자원 고갈 (resource exhaustion, 스레드 고갈, pool exhaustion)
요청마다 스레드·커넥션을 새로 잡다가 메모리나 한도가 바닥나 새 작업을 받지 못하는 상태. 풀이면 모든 워커가 막혀 대기열만 느는 모양으로 나타난다
잠금 순서 고정 (lock ordering)
여러 행을 잠글 때 항상 같은 순서(예: id 오름차순)로 잠근다. 서로 반대 순서로 잠가 생기는 교착을 구조적으로 없앤다
처리량 (throughput, TPS)
단위 시간에 끝낸 작업 수. 동시성을 늘리는 목적이고, 경합이 커지면 오히려 줄어든다
컨텍스트 스위칭 (context switch)
CPU 가 실행 중인 스레드의 레지스터·스택 상태를 저장하고 다른 스레드 상태로 바꾸는 일. 수 마이크로초가 들고 캐시가 식는다. 스레드가 많을수록 이 비용이 커진다
코루틴 (coroutine)
중단 지점에서 스스로 멈췄다가 이어서 실행되는 경량 실행 단위. 멈춘 동안 스레드를 놓아 주므로 적은 스레드로 많은 IO 대기를 겹칠 수 있다
async/await (async await, Deferred, launch/async)
비동기 작업을 시작해 두고(async) 결과가 필요한 자리에서 기다리는(await) 방식. 콜백 없이 순차 코드 모양으로 여러 IO 를 겹친다
CAS (compare-and-swap, compareAndSet, CAS, compare-and-exchange)
메모리 값이 기대값과 같을 때만 새 값으로 바꾸는 CPU 원자 명령. 실패하면 다시 읽고 재시도한다. 락-프리 자료구조와 원자 변수가 이 위에 선다
SKIP LOCKED 작업 나눠 갖기 (FOR UPDATE SKIP LOCKED, NOWAIT)
FOR UPDATE SKIP LOCKED 로 이미 잠긴 행은 건너뛰고 나머지만 가져간다. 여러 워커가 같은 테이블을 큐처럼 나눠 처리할 때 서로 기다리지 않는다

다른 분류