쓰레드 동기화 Synchronized
휴대폰으로 음악이나 영상을 동기화하면 동기화가 끝날때까지 다른 작업을 할 수 없는데 이런 구조가 바로 동기화 쓰레드의 구조이다. 두 개 이상의 쓰레드가 하나의 자원을 공유할 경우 동기화 문제가 발생한다. 변수는 하나인데 두 개의 쓰레드가 하나의 동시에 한 변수의 값을 변경하려고 하기 때문이다. 이를 막기 위해 작업이 끝날때까지 다른 접촉이 발생하지 않도록 잠가둘 필요가 있다.
package java12;
class SyncEx implements Runnable {
private long money = 10000;
@Override
public void run() {
synchronized (SyncEx.class) { //인자가 this.SyncEx
// synchrosized 키워드가 명시되어있는 구역은
// 다른 쓰레드에서 접근하지 못하게 막는다.
for (int i=0; i<10; i++) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
if (getMoney() <= 0) {
break;
}
outMoney(1000);
}
} // 여기까지 타스레드 접근불가
}
public long getMoney() { //getter()
return money;
}
/* public void setMoney(long money) { //setter()
this.money = money;
} */
public void outMoney (long howMuch) {
String threadName = Thread.currentThread().getName();
if (getMoney() > 0) {
money -= howMuch;
System.out.println(threadName+ " - 잔액 : " +getMoney()+ "원");
}
if (getMoney() == 0 ) {
System.out.println(threadName + " - 잔액이 없습니다.");
}
}
}
public class Test05 {
public static void main(String[] args) {
SyncEx atm = new SyncEx();
Thread mom = new Thread(atm, "엄마");
Thread son = new Thread(atm, "아들");
mom.start(); //start를 실행하면 내부적으로 run이 실행되므로 오버라이드 에러가 없음
son.start();
}
}
mom.start와 son.start 두개가 실행되었지만 먼저실행된 mom부분이 synchrosize로 접근을 막아 son.start는 출력이 되지않았다.
10번행을 다음과같이 바꿀경우

mom에서 6천원만 빠져나간후에 syncronized된 쓰레드가 종료된 후 son이 실행되므로 다음과 같이 결과가 나온다.

쓰레드에서 wait(), notify()
현재 실행중인 스레드가 진행중에 wait() 메서드를 만나면 일시적으로 정지되며 대기상태로 보내지고 제어권을 다른 쓰레드에게 넘긴다. 그리고 대기상태가 된 쓰레드는 notify()를 만나면 재구동 된다.
이런기법을 이용하면 두 개 이상의 쓰레드가 구동중일때 한 개의 동기화 쓰레드가 작업을 진행하면 이 작업을 완전히 마칠 때 까지 기다렸다가 다른 쓰레드의 작업이 수행되는 것이 아니라, 하나의 쓰레드 동기화가 진행중일 때에도 일시적으로 해당 쓰레드를 정지시키고 다른 쓰레드가 작업을 할 수 있게 만들 수 있다.
package java12;
import java.util.Random;
import java.util.Scanner;
class Account {
int balance = 1000; //잔액
public synchronized void withdraw(int money) {
if (balance < money) {
try {
System.out.println("얼마 입금하실건가요?");
wait(); // 쓰레드 정지, 대기상태
} catch (Exception e) {}
}
balance -= money;
}
public synchronized void deposit(int money) {
balance += money;
notify(); // 대기상태인 쓰레드 실행
}
}
class AccountThread implements Runnable {
Account acc; // Account 객체 acc준비
public AccountThread(Account acc) { //생성자
this.acc = acc;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch(Exception e) {}
int money = (new Random().nextInt(3) + 1) * 100;
acc.withdraw(money);
System.out.println("잔액 : " +acc.balance);
}
}
}
public class Test06 {
public static void main(String[] args) {
Account acc = new Account();
Runnable rr = new AccountThread(acc);
Thread td = new Thread(rr);
td.start();
while (true) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
acc.deposit(n);
}
}
}
'코딩 > JAVA' 카테고리의 다른 글
JAVA 29-1. 컬렉션 프레임워크 - MAP (0) | 2022.08.08 |
---|---|
JAVA 29. 컬렉션 프레임워크 (0) | 2022.08.08 |
JAVA 28. 쓰레드 (0) | 2022.08.08 |
JAVA 27. 예외 (0) | 2022.08.08 |
JAVA 26. 내부 클래스 (0) | 2022.07.31 |