synchronized 키워드
•
스레드가 하나의 자원을 사용하고자 할 때, 해당 스레드만 제외하고 나머지 스레드는 자원에 접근 못하도록 막는 것을 동기화라고 한다.
•
자바에서의 synchronized는 객체에 대한 동기화 로 이루어지며, 이는 동기화된 블록에는 한 시점에는 하나의 스레드만이 접근 및 실행 되도록 조정한다.
예시
public class ThreadSyncEx {
public static void main(String[] args) {
Runnable thread = new CreateThread();
// 2개의 작업 스레드 생성
Thread thread1 = new Thread(thread);
Thread thread2 = new Thread(thread);
thread1.setName("스레드1");
thread2.setName("스레드2");
thread1.start();
thread2.start();
}
}
class Money {
// 현재 가지고 있는 금액
private int myMoney = 10000;
public int getMyMoney() {
return myMoney;
}
public boolean withdraw(int money) {
// 가지고 있는 금액이 출금할 금액보다 크거나 같을 때만 출금
if (myMoney >= money) {
// 스레드 동시 접근을 위한 코드
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println(e);
}
// 출금
myMoney -= money;
return true;
}
return false;
}
}
class CreateThread implements Runnable {
Money myMoney = new Money();
public void run() {
while (myMoney.getMyMoney() > 0) {
// 1000 ~ 5000원씩 출금
int money = (int)(Math.random() * 5 + 1) * 1000;
// 출금 실행 코드. 실패시 true 반환
boolean denied = !myMoney.withdraw(money);
// 출금 과정 출력
if (denied) {
System.out.println("출금 거부");
} else {
System.out.printf("스레드: %s 출금: %d원 남은금액: %d원\\n",
Thread.currentThread().getName(), money, myMoney.getMyMoney());
}
}
}
}
Java
복사
// 출력 (실행할 때마다 결과는 달라진다.)
스레드: 스레드1 출금: 5000원 남은금액: 5000원
스레드: 스레드2 출금: 2000원 남은금액: 5000원
스레드: 스레드2 출금: 1000원 남은금액: 4000원
출금 거부
스레드: 스레드1 출금: 1000원 남은금액: 3000원
스레드: 스레드2 출금: 2000원 남은금액: -2000원
스레드: 스레드1 출금: 3000원 남은금액: -2000원
Java
복사
synchronized 키워드를 임계 영역으로 지정할 메서드의 반환 타입 앞에 입력하여 메서드 전체를 임계 영역으로 설정할 수 있다
class Money {
private int myMoney = 10000;
public int getMyMoney() {
return myMoney;
}
// 메서드 전체를 임계영역으로 설정
public synchronized boolean withdraw(int money) {
if (myMoney >= money) {
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println(e);
}
myMoney -= money;
return true;
}
return false;
}
}
Java
복사
// 출력
스레드: 스레드1 출금: 1000원 남은금액: 9000원
스레드: 스레드2 출금: 2000원 남은금액: 7000원
스레드: 스레드1 출금: 4000원 남은금액: 3000원
출금 거부
출금 거부
스레드: 스레드1 출금: 3000원 남은금액: 0원
Java
복사
Reentrant Lock이란?
ReentrantLock은 동기화된 메소드와 문장을 사용하여 액세스할 수 있는 암시적인 모니터 잠금 기능과 같은 기본적인 의미를 가진 Reentrant 상호 간의 상호 배제된 상호 배제 잠금을 의미한다.
•
잠금 영역과 잠금을 푸는 영역을 수동적으로 설정할 수 있다.
•
ReentrantLock 객체는 선언 시 private final로 선언한다.
•
동기화하고 싶은 구역의 앞부분에 참조 변수명.lock으로 해당 구문을 잠가준다. 그리고 동기화 내용을 try 안에 적어준 뒤, finally를 사용하여 참조 변수명.unlock하여 잠가둔 구역을 풀어준다.
//기본적인 사용법
class TestClass{
private ReentrantLock lock = new ReentrantLock(); // Lock 생성
public testMethod(){
lock.lock();
try{
//Critical Section
} finally {
lock.unlock();
}
}
}
Java
복사