[java] concurrent package 정리
java.util.concurrent는 java 5 에서 추가된 패키지로 동기화에 필요한 다양한 클래스를 제공하는 패키지이다.
- Executors : 스레드 풀 생성, 스레드 재사용, task등록과 실행등을 간편하게 처리할 수 있다.
- Atomic : 동기화 되어 있는 변수를 제공한다. Automic_ 접두어가 붙는 클래스.
- Locks : 상호배제를 사용할 수 있는 클래스를 제공한다.
- Queues : 컬렉션 프레임워크에서 제공하는 선입선출(FIFO) 방식의 데이터 처리 흐름이며 컨커런트 api에서 제공하는 큐는 thread-safe 하다.
- Synchronizers : 동기화 관련된 5가지 유틸리티를 제공한다. 동시에 실행할 수 있는 스레드의 크기를 제한하는 기능을 제공하며 Semaphore 클래스를 이용하면 쉽게 구현할 수 있다.
java.util.concurrent.locks
synchronized 블록을 사용하면 자동으로 lock이 잠기고 풀리며 블럭 내에 예외가 발생해도 lock이 자동으로 풀려 편하다. 그러나 큐의 스레드들은 순서를 지키며 lock을 확보하게 되는데 만약 lock이 필요한 순간 release되면서 대기열을 건너띄는 순간 다른 스레드에게 우선순위가 밀려 자원을 계속해서 할당 받지 못하는 순간이 생기게 되는데 이럴경우 공정성이 어긋난다. Lock을 사용하게 되면 여러 스레드가 경쟁상태에 있을때 가장 오래 기다린 스레드에게 lock을 제공하여 공정성 있게 모든 스레드가 작업을 수행할 기회를 얻게 된다. 특정 조건에서 lock을 풀고 나중에 다시 lock을 얻을 수 있게 된다. 또한 lock()과 unlock()으로 시작과 끝을 명시하기 때문에 임계영역을 여러 메서드에 나눠서 작성할 수 있다.
- ReentrantLock : Lock인터페이스의 구현체로 특정 조건에서 lock이 풀렸을때 대기 없이 다시 lock을 얻고 이후의 작업을 수행할 수 있다.
- ReentrantReadWriteLock : ReadWriteLock의 구현체로 읽기락과 쓰기락을 제공하는데 여러쓰레드는 읽기락을 중복해서 걸고 읽기를 수행할 수 있지만 쓰기락에는 배타적이며 읽기락이 걸려있을때 쓰기락을 획득할 수 없고 그 반대도 마찬가지이다.
- StampedLock : 읽기락과 쓰기락 외에 낙관적 읽기 기능이 추가된다. 읽기락이 걸려있으면 쓰기락을 얻기위해서는 읽기락이 풀릴때까지 기다려야 하는데 낙관적 읽기락은 쓰기 락에 의해 바로 풀린다. 반대 모드로 락을 전환시키는데 이것을 upgrade라고 한다. 읽기와 쓰기가 충돌할때 사용한다.
java.util.concurrent.atomic
원자적 연산을 수행하기 위한 연산들을 포함한 패키지이다.
@Test
@DisplayName("동일한 아이디로 회원가입 동시 요청 5번 일때 1번 성공, 4번 실패")
void joinWithConcurrencyControl() throws InterruptedException {
final int threadCount = 5;
AtomicInteger throwCount = new AtomicInteger(0);
ExecutorService service = Executors.newFixedThreadPool(threadCount);
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
service.execute(() -> {
try {
fSignupService.signup(SIGNUP_REQUEST);
} catch (DuplicationException e) {
throwCount.getAndIncrement();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
Assertions.assertEquals(throwCount.get(), threadCount-1);
}
자바 동기화 클래스
멀티 스레드 환경에서 하나의 프로세스는 다수의 스레드에 의해 실행된다. 스레드가 사용하는 독립적인 자원을 제외하고 스레드끼리 공유하는 자원 [ 스택 영역 제외 ] 을 사용하려면 동기화 작
kiwideveloper.tistory.com
ThreadPoolExecutor을 이용한 효율적인 멀티쓰레드 이용
쓰레드 풀을 사용하는 이유 병렬 작업 처리가 많아지면 쓰레드의 개수가 늘어나고, 쓰레드의 생성과 스케줄링으로 인해 CPU의 사용률이 저하되고, 메모리의 사용량이 늘어난다. 이렇게 되면 어
kiwideveloper.tistory.com