Files
java-examples/docs/Concurrency.md

225 lines
6.8 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 자바 동시성(Concurrency) API 정리 및 쉬운 설명
자바의 동시성(Concurrency) API는 **멀티스레딩을 효율적으로 관리하고 안전하게 실행할 수 있도록 지원하는 기능**을 제공한다.
즉, **여러 작업을 동시에 실행하여 프로그램 성능을 향상**시킬 수 있다.
---
## 1. 주요 클래스 및 메서드 정리
### (1) `Thread` 클래스 (기본 스레드 실행)
| 메서드 | 설명 |
|--------|------------------------------|
| `start()` | 새로운 스레드를 실행 |
| `run()` | 실행할 코드 정의 (직접 호출하면 동작하지 않음) |
| `sleep(ms)` | 지정된 시간(ms) 동안 스레드 일시 정지 |
| `join()` | 현재 스레드가 종료될 때까지 다른 스레드 대기 |
| `interrupt()` | 실행 중인 스레드를 인터럽트 (깨우기) |
| `isAlive()` | 스레드가 실행 중인지 확인 |
**사용 예시:**
```java
class MyThread extends Thread {
public void run() {
System.out.println("스레드 실행 중!");
}
}
MyThread t = new MyThread();
t.start(); // 스레드 실행
```
---
### (2) `Runnable` 인터페이스 (스레드 실행)
| 메서드 | 설명 |
|--------|------------------------------|
| `run()` | 실행할 코드 정의 |
**사용 예시:**
```java
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable 스레드 실행!");
}
}
Thread t = new Thread(new MyRunnable());
t.start();
```
`Thread` 클래스를 직접 상속하지 않고 `Runnable`을 구현하여 사용.
---
### (3) `ExecutorService` (스레드 풀)
| 메서드 | 설명 |
|--------|------------------------------|
| `submit(Runnable)` | 스레드를 실행 (결과 없음) |
| `submit(Callable<T>)` | 스레드를 실행하고 결과 반환 |
| `shutdown()` | 스레드 풀 종료 (기존 작업 수행 후 종료) |
| `shutdownNow()` | 즉시 모든 작업 중단 |
**사용 예시:**
```java
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> System.out.println("스레드 풀에서 실행"));
executor.shutdown();
```
`Executors.newFixedThreadPool(2)`를 사용해 2개의 스레드를 관리.
---
### (4) `Callable` & `Future` (결과 반환이 필요한 작업)
| 메서드 | 설명 |
|--------|------------------------------|
| `call()` | 실행할 코드 정의, 결과 반환 |
| `get()` | `Future`에서 결과 가져오기 (블로킹) |
| `isDone()` | 작업 완료 여부 확인 |
**사용 예시:**
```java
Callable<Integer> task = () -> {
Thread.sleep(1000);
return 10;
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(task);
System.out.println(future.get()); // 결과 가져오기
executor.shutdown();
```
`Callable`을 사용하면 **스레드 실행 후 결과 값을 반환**할 수 있음.
---
### (5) `ReentrantLock` (락을 이용한 동기화)
| 메서드 | 설명 |
|--------|------------------------------|
| `lock()` | 락 획득 |
| `unlock()` | 락 해제 |
| `tryLock()` | 락을 시도하고 성공하면 `true` 반환 |
**사용 예시:**
```java
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
System.out.println("임계영역 실행");
} finally {
lock.unlock();
}
```
`synchronized` 키워드 대신 `ReentrantLock`을 사용하여 더 정교한 동기화 가능.
---
### (6) `Semaphore` (동시 실행 제한)
| 메서드 | 설명 |
|--------|------------------------------|
| `acquire()` | 리소스 사용 요청 (없으면 대기) |
| `release()` | 사용한 리소스 반환 |
**사용 예시:**
```java
Semaphore semaphore = new Semaphore(2);
semaphore.acquire(); // 사용 가능하면 진행, 아니면 대기
System.out.println("리소스 사용 중");
semaphore.release();
```
→ 한 번에 2개의 스레드만 특정 코드 실행 가능.
---
### (7) `CountDownLatch` (스레드가 모두 끝날 때까지 대기)
| 메서드 | 설명 |
|--------|------------------------------|
| `await()` | 모든 스레드가 완료될 때까지 대기 |
| `countDown()` | 하나의 작업 완료 처리 |
**사용 예시:**
```java
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("작업 완료");
latch.countDown();
}).start();
}
latch.await();
System.out.println("모든 작업 완료");
```
→ 모든 작업(`countDown()` 3회)이 끝나야 `await()`이 풀림.
---
### (8) `CyclicBarrier` (스레드가 모두 도달할 때까지 대기)
| 메서드 | 설명 |
|--------|------------------------------|
| `await()` | 지정된 개수의 스레드가 모일 때까지 대기 |
**사용 예시:**
```java
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("모든 스레드 도착!");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("스레드 실행 중");
barrier.await();
}).start();
}
```
`CyclicBarrier`는 정해진 개수의 스레드가 모두 도착할 때까지 기다림.
---
## 2. 자바 동시성 쉽게 설명하기
자바에서 동시성을 다룰 때 중요한 개념은 **멀티스레딩과 스레드 동기화**다.
즉, 여러 개의 스레드가 **같은 자원을 동시에 접근하면 충돌이 발생**할 수 있으므로, 이를 적절히 제어해야 한다.
### 1⃣ **기본적인 멀티스레드**
- `Thread` 또는 `Runnable`을 사용해 실행
- `start()`로 실행, `join()`으로 대기
### 2⃣ **스레드 풀 사용 (`ExecutorService`)**
- 직접 스레드를 생성하면 관리가 어렵기 때문에, **스레드 풀을 사용하여 성능 최적화**
- `submit()`으로 작업을 실행하고, `shutdown()`으로 종료
### 3⃣ **결과를 받아야 한다면? (`Callable` & `Future`)**
- `Callable`을 사용하면 작업이 끝난 후 결과 값을 반환 가능
- `future.get()`을 호출하면 결과를 가져올 수 있음
### 4⃣ **공유 자원 충돌 방지 (`ReentrantLock`, `synchronized`)**
- `synchronized` 키워드는 단순하지만 유연성이 낮음
- `ReentrantLock`은 더 정교한 동기화 제공
### 5⃣ **특정 조건을 만족할 때 실행 (`CountDownLatch`, `CyclicBarrier`)**
- `CountDownLatch` → 여러 개의 스레드가 끝날 때까지 대기
- `CyclicBarrier` → 여러 스레드가 동시에 도달해야 실행
---
## 3. 정리
✅ 멀티스레딩을 쉽게 하려면? → `ExecutorService`
✅ 스레드 실행 결과를 받아야 한다면? → `Callable`, `Future`
✅ 여러 스레드가 동시에 공유 자원을 사용하면? → `ReentrantLock`, `synchronized`
✅ 여러 작업이 끝난 후 실행되게 하려면? → `CountDownLatch`, `CyclicBarrier`
즉, **자바 동시성 API를 적절히 활용하면 멀티스레딩을 효율적으로 관리할 수 있다!**