Skip to content

Java Concurrent패키지

sue06004 edited this page Jul 13, 2023 · 3 revisions

Concurrent패키지

java.util.concurrent 패키지

java.util.concurrent패키지는 Java5 에서 추가된 패키지로, 동기화가 필요한 상황에서 사용할 수 있는 다양한 유틸리티 클래스들을 제공한다.

  • Locks : 상호 배제를 사용할 수 있는 클래스를 제공한다.
  • Atomic : 동기화가 되어있는 변수를 제공한다.
  • Executors : 스레드 풀 생성, 스레드 생명주기 관리, Task 등룍과 실행 등을 간편하게 처리할 수 있다.
  • Queue : thread-safe한 FIFO 큐를 제공한다.
    • tread-safe : 멀티 스레드 프로그래밍에서 일반적으로 어떤 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없는 것을 말한다.
  • Synchronizers : 특수한 목적의 동기화를 처리하는 5개의 클래스를 제공한다.
    • Semaphore, CountDownLatch, CyclicBarrier, Phaser, Exchanger

Locks

java.util.concurrent.locks패키지엔 상호 배제를 위한 Lock API가 정의 되어 있다. java의 synchronized블록을 사용했을 때와 동일한 매커니즘으로 동작한다. 내부적으로 synchronized를 사용해ㅐ 구현되었으며, synchronized를 더욱 유연하고 정교하게 처리하기 위한 것이지 대체하는 목적을 가지진 않는다.

Lock Interface and ReentrantLock(구현체)

  • lock() : Lock인스턴스에 잠금을 걸어둔다. Lock인스턴스가 이미 잠겨 있는 상태라면, unlock()이 실행될 때 까지 lock을 실행한 쓰레드가 비활성화 된다.
  • lockInterruptibly() : 현재 쓰레드가 intterupted 상태가 아닐 때 Lock 인스턴스에 잠금을 건다. 현재 쓰레드가 intterupted 상태면 InterruptedException를 발생시킨다.
  • tryLock() : 즉시 Lock 인스턴스에 잠금을 시도하고 성공 여부를 boolean 타입으로 반환한다.
  • unLock() : Lock인스터스의 잠금을 해제한다.

Executors

ExecutorService는 Thread를 생성하고 처리하고 제거하는 등 병렬 프로그래밍을 위한 인터페이스이다. ThreadPool을 구현하고 관리하는 역할을 한다. submit()을 사용하면 작업을 ExecutorService가 만든 쓰레드풀에서 처리힌다. shutdown()은 쓰레드 풀을 종료한다.

ExecutorService = Executors.newFixedThreadPool(int nThreads)

최대 지정한 개수 만큼의 쓰레드를 가질 수 있는 쓰레드 풀을 생성한다. 실제 생성되는 객체는 ThreadPoolExecutor객체이다. 항상 일정한 스레드 개수를 유지한다. 다만 비정상적으로 쓰레드가 종료되는 경우 스레드를 추가로 생성하며, 지정한 개수보다 1개가 더 생길 수도 있다.

ScheduledExecutorService = Executors.newScheduledThreadPool(int corePoolSize)

지정한 개수만큼 쓰레드가 유지되는 스케줄 가능한 쓰레드 풀을 생성한다. 실제 생성되는 객체는 ScheduledThreadPoolExecutor객체이다.

ExecutorService = Executors.newSingleThreadExecutor()

하나의 쓰레드만 사용하는 ExecutorService를 생성한다. 항상 1개의 쓰레드만 동작한다. 따라서 쓰레드가 동작중일 경우 나머지 작업은 모두 큐에서 대기하며, 순서대로 하나씩 수행된다.

ExecutorService = Executors.newCachedThreadPool()

필요할 때 마다 쓰레드를 생성하는 쓰레드 풀을 생성한다. 이미 생성된 쓰레드의 경우 재사용된다. 실제 생성되는 객체는 ThreadPoolExecutor객체이다. 쓰레드 개수에 제한이 없이 필요한 경우 쓰레드 수가 증가한다. 다만 일정 시간(60초)동안 사용하지 않는 쓰레드는 종료된다. 쓰레드 생성과 삭제를 반복하므로 작업 부하가 불규칙적인 경우 비효율적이다.

Synchronizer

CountDownLatch

  • 어떤 스레드가 다른 쓰레드에서 작업이 완료될 때 까지 기다릴 수 있도록 해주는 클래스

CountDownLatch countDownLatch = new CountDownLatch(5);
다음과 같이 countDown()을 호출하면 Latch의 숫자가 1개씩 감소한다.
countDownLatch.countDown();
await()는 Latch의 숫자가 0이 될 때까지 기다리는 코드이다.
countDownLatch.await();
다른 쓰레드에서 countDown()을 5번 호출하게 된다면 Latch는 0이 되며, await()은 더 이상 기다리지 않고 다음 코드를 실행하게 된다.

CyclicBarrier

  • 동시에 실행되는 쓰레드 내부 원하는 지점에서 대기를 걸어주고 모든 쓰레드가 대기 상태에 들어갔을 때, 대기를 풀어주는 동작을 한다.

CyclicBarrier cyclicBarrier = new CyclicBarrier(n);
cyclicBarrier.await();

References

https://jenkov.com/tutorials/java-util-concurrent/lock.html#lock-and-reentrantlock-methods https://hamait.tistory.com/381 https://memo-the-day.tistory.com/120 https://codechacha.com/ko/java-countdownlatch/