동기화
동기화는 다수의 프로세스나 스레드에서 공유 자언에 동시에 접근할 때 발생할 수 있는 문제를 해결하기 위한 기술입니다.
여러 프로세스나 스레드가 동시에 공유 자원을 수정하거나 읽을 때, 일관된 순서로 접근하여 데이터의 일관성 보장의 목표
프로세스 동기화
컴퓨터 시스템에서 여러 프로세스가 동시에 실행될 때 발생할 수 있는 문제를 해결하는 기술입니다.
동기화의 목적
상호 배제
동일한 자원에 대해 여러 프로세스나 스레드가 동시에 접근하지 못하도록 제어하는 것을 말하며, 즉, 한 프로세스나 스레드가 자원을 사용하고 있을 때에는 다른 프로세스나 스레드는 접근할 수 없도록 해야 합니다.
예를 들면, 계좌에 저축하는 프로세스 A와 B가 있을 때 A가 자원을 사용하는 동안 B는 대기하고, A작업이 끝난 후에 B가 자원에 접근하는 방식으로 이렇게 함으로 충돌을 방지하고 안전하게 자원을 사용할 수 있습니다.
순서 보장
동기화를 통해 어떤 프로세스나 스레가 자원에 접근할 때 순서를 보장하여 일관성을 유지하는 것을 말하며 예를 들면, 여러 프로세스나 공유 자원에 접근하게 되는데 먼저 요청한 프로세스가 먼저 접근할 수 있도록 순서를 정하는 것이 해당됩니다.
동기화 구분 방법
뮤텍스, 세마포어, 모니터등으로 동기화 기법으로, 공유 자원에 대한 접근을 조절하고 상호 배제를 보장하는 데 사용합니다.
뮤텍스
뮤텍스는 상호배제를 위한 동기화 메커니즘 중 하나로, 오직 하나의 스레드만이 특정 자원에 접근할 수 있도록 하는 동기화 객체입니다. 뮤텍스는 임계 영역에 진입하기 전에 락을 획득하고, 임계영역을 벗어날 때 락을 해제하여 다른 스레드가 접근할 수 있도록 합니다.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AccountExample {
private static int balance = 100000; // 초기 계좌 잔액
private static Lock mutex = new ReentrantLock(); // 뮤텍스 생성
public static void depositMoney(int amount) {
mutex.lock(); // 뮤텍스 락 획득
try {
balance += amount; // 잔액 증가
} finally {
mutex.unlock(); // 뮤텍스 락 해제
}
}
public static void main(String[] args) throws InterruptedException {
// A 스레드: 2만 원을 입금
Thread threadA = new Thread(() -> {
depositMoney(20000);
});
// B 스레드: 5만 원을 입금
Thread threadB = new Thread(() -> {
depositMoney(50000);
});
// 두 개의 스레드 실행
threadA.start();
threadB.start();
// 메인 스레드가 두 스레드의 작업을 기다림
threadA.join();
threadB.join();
// 잔액 출력
System.out.println("잔액: " + balance + "원");
}
}
세마포어
세마포어는 뮤텍스와 유사하게 상호배제를 제공하지만, 뮤텍스와는 다르게 동시에 여러 개의 스레드 임계 영역에 진입할 수 있도록 허용하는 카운팅 기반의 동기화 객체입니다. 세마포어는 허용 가능한 스레드의 개수를 제어하는 카운터 역할도 합니다.
import java.util.concurrent.Semaphore;
public class AccountExample {
private static int balance = 100000; // 초기 계좌 잔액
private static Semaphore semaphore = new Semaphore(1); // 세마포어 생성 (허용 가능한 스레드 개수: 1)
public static void depositMoney(int amount) throws InterruptedException {
semaphore.acquire(); // 세마포어 획득
try {
balance += amount; // 잔액 증가
} finally {
semaphore.release(); // 세마포어 해제
}
}
public static void main(String[] args) throws InterruptedException {
// A 스레드: 2만 원을 입금
Thread threadA = new Thread(() -> {
try {
depositMoney(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// B 스레드: 5만 원을 입금
Thread threadB = new Thread(() -> {
try {
depositMoney(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 두 개의 스레드 실행
threadA.start();
threadB.start();
// 메인 스레드가 두 스레드의 작업을 기다림
threadA.join();
threadB.join();
// 잔액 출력
System.out.println("잔액: " + balance + "원");
}
}
모니터
고급 프로그래밍 언어에서 제공되는 추상화된 동기화 메커니즘입니다. 모니터는 임계 영역에 대한 접근을 제어하고 상호배제를 구현하며, 스레드 간의 통신을 돕는다는 것은 뮤텍스와 유사하지만 좀 더 추상화된 형태로 제공됩니다. 또한 모니터는 언어에 따라 구현이 다를 수 있지만, 대부분 임계 영역에 진입하기 위한 키워드나 메서드를 제공하여 사용합니다.