add user agent parser and update build configuration

This commit is contained in:
2025-03-11 11:32:36 +09:00
parent 3db3499d30
commit 09731f464d
47 changed files with 8825 additions and 18 deletions

View File

@@ -0,0 +1,193 @@
### 자바 스레드 동기화에 대한 설명
스레드 동기화는 멀티스레드 환경에서 여러 스레드가 공유 자원(예: 변수, 객체 등)에 동시에 접근할 때 발생할 수 있는 데이터 불일치 문제를 해결하기 위해 사용됩니다. 자바에서는 동기화를 통해 특정 코드 블록이나 메서드가 한 번에 하나의 스레드만 실행하도록 보장합니다. 이를 통해 **경쟁 조건(race condition)**을 방지하고, 데이터의 무결성을 유지할 수 있습니다.
자바에서 스레드 동기화를 구현하는 주요 방법은 `synchronized` 키워드와 `java.util.concurrent` 패키지의 도구(예: `Lock`, `Semaphore` 등)를 사용하는 것입니다. 아래에서는 `synchronized` 키워드를 중심으로 설명하고, 예시를 제공하겠습니다.
---
### 스레드 동기화의 필요성
예를 들어, 은행 계좌 잔액을 관리하는 프로그램에서 두 스레드가 동시에 잔액을 수정하려고 하면 문제가 발생할 수 있습니다. 동기화가 없으면 잔액이 잘못 계산될 가능성이 높습니다. 이를 **경쟁 조건**이라고 부르며, 동기화로 해결할 수 있습니다.
---
### `synchronized` 키워드 사용 방법
자바에서 동기화는 두 가지 방식으로 적용됩니다:
1. **`synchronized` 메서드**: 메서드 전체를 동기화하여 한 번에 하나의 스레드만 실행하도록 만듭니다.
2. **`synchronized` 블록**: 특정 코드 블록만 동기화하여 더 세밀한 제어가 가능합니다.
---
### 예시 1: 동기화 없는 경우 (문제 발생)
아래는 동기화 없이 두 스레드가 계좌 잔액을 동시에 수정하는 예시입니다.
```java
class BankAccount {
private int balance = 1000; // 초기 잔액
public void withdraw(int amount) {
if (balance >= amount) {
System.out.println(Thread.currentThread().getName() + " 출금 시도: " + amount);
balance -= amount; // 잔액 감소
System.out.println(Thread.currentThread().getName() + " 출금 후 잔액: " + balance);
}
}
public int getBalance() {
return balance;
}
}
public class NoSyncExample {
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread t1 = new Thread(() -> {
account.withdraw(800);
}, "스레드1");
Thread t2 = new Thread(() -> {
account.withdraw(800);
}, "스레드2");
t1.start();
t2.start();
}
}
```
- **출력 예시 (무작위 결과)**:
```
스레드1 출금 시도: 800
스레드2 출금 시도: 800
스레드1 출금 후 잔액: 200
스레드2 출금 후 잔액: -600
```
- **문제**: 두 스레드가 동시에 `withdraw`를 호출하면서 잔액이 음수가 되는 비정상적인 결과 발생. 이는 `if (balance >= amount)` 조건을 확인한 후 `balance -= amount`가 실행되기 전에 다른 스레드가 끼어들었기 때문입니다.
---
### 예시 2: `synchronized` 메서드로 동기화
`withdraw` 메서드에 `synchronized`를 적용하면 한 번에 하나의 스레드만 메서드를 실행할 수 있습니다.
```java
class BankAccount {
private int balance = 1000;
public synchronized void withdraw(int amount) {
if (balance >= amount) {
System.out.println(Thread.currentThread().getName() + " 출금 시도: " + amount);
try {
Thread.sleep(100); // 경쟁 조건 시뮬레이션
} catch (InterruptedException e) {
e.printStackTrace();
}
balance -= amount;
System.out.println(Thread.currentThread().getName() + " 출금 후 잔액: " + balance);
} else {
System.out.println(Thread.currentThread().getName() + " 잔액 부족");
}
}
public int getBalance() {
return balance;
}
}
public class SyncMethodExample {
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread t1 = new Thread(() -> {
account.withdraw(800);
}, "스레드1");
Thread t2 = new Thread(() -> {
account.withdraw(800);
}, "스레드2");
t1.start();
t2.start();
}
}
```
- **출력 예시**:
```
스레드1 출금 시도: 800
스레드1 출금 후 잔액: 200
스레드2 출금 시도: 800
스레드2 잔액 부족
```
- **설명**: `synchronized` 덕분에 첫 번째 스레드가 `withdraw`를 완료할 때까지 두 번째 스레드가 대기하며, 잔액이 음수로 떨어지지 않음.
---
### 예시 3: `synchronized` 블록으로 동기화
메서드 전체가 아닌 특정 코드 블록만 동기화하려면 `synchronized` 블록을 사용합니다. 이때 동기화 대상 객체(락 객체)를 지정해야 합니다.
```java
class BankAccount {
private int balance = 1000;
private final Object lock = new Object(); // 락 객체
public void withdraw(int amount) {
System.out.println(Thread.currentThread().getName() + " 출금 시도: " + amount);
synchronized (lock) { // 동기화 블록
if (balance >= amount) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance -= amount;
System.out.println(Thread.currentThread().getName() + " 출금 후 잔액: " + balance);
} else {
System.out.println(Thread.currentThread().getName() + " 잔액 부족");
}
}
}
public int getBalance() {
return balance;
}
}
public class SyncBlockExample {
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread t1 = new Thread(() -> {
account.withdraw(800);
}, "스레드1");
Thread t2 = new Thread(() -> {
account.withdraw(800);
}, "스레드2");
t1.start();
t2.start();
}
}
```
- **출력 예시**:
```
스레드1 출금 시도: 800
스레드2 출금 시도: 800
스레드1 출금 후 잔액: 200
스레드2 잔액 부족
```
- **설명**: `synchronized (lock)` 블록 내의 코드만 동기화되며, `lock` 객체를 통해 스레드 간 접근을 제어함. 메서드 전체를 동기화하는 것보다 유연성이 높음.
---
### 동기화의 장점과 주의점
- **장점**:
- 공유 자원에 대한 안전한 접근 보장.
- 데이터 무결성 유지.
- **주의점**:
- 과도한 동기화는 성능 저하(데드락, 스레드 대기 시간 증가)를 유발할 수 있음.
- 필요한 범위만 동기화하도록 설계해야 함.
---
### 결론
스레드 동기화는 멀티스레드 프로그래밍에서 필수적인 개념으로, 자바에서는 `synchronized` 키워드를 통해 간단히 구현할 수 있습니다. `synchronized` 메서드와 블록을 적절히 사용하면 경쟁 조건을 방지하고 안정적인 프로그램을 작성할 수 있습니다. 위 예시를 참고하여 실제 애플리케이션에서 동기화를 적용해 보세요!