스레드 동기화(synchronized)

어느 주어진 시간에는 하나의 스레드만이 동일한 자료를 참조할 수 있도록 제한하는 방법
synchronized는 메소드에 사용이 가능한 modifier로서, 여러 스레드에 의해 특정 객체의 메소드들이
동시 호출되는 것에 대해 잠금을 설정하여, 거부하도록 하는 기능을 지원한다.
즉 코드의 한부분, 또는 동기화된 메소드가 다른 스레드와 동시에 수행될 수 없게 하는 것

package day26;

import java.util.Random;

public class Account {
	private int money=10;
	private boolean flag= false;
	//메소드 앞에 synchronized라는 modifier를 붙인다.
	//그러면 스레드는 Account객체의 lock을 소유해야만 get메소드를 수행할 수 있다.
	synchronized public void get(int val) {
		if(!flag) {
			try {
				wait();
				//출금하러 왔다가 lock이 걸린다.
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if(money-val<0) {
			System.out.println("잔금이 부족합니다.");
			notify();
			return;
		}
		money-=val;
		System.out.println("출금액: "+val+", 출금후 잔액: "+money);
		flag=false;
		notify();
	}
	
	public void save(int val) {
		synchronized (this) {
			if(flag) {				
				try {
					wait();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			money+=val;
			System.out.println("입금액: "+val+", 입금후 잔액: "+money);
			flag=true;
			notify();
		}
	}
}

class UserIn extends Thread{
	Account ac;
	public UserIn(Account ac, String name) {
		this.ac=ac;
		this.setName(name); // thread의 이름을 name으로 설정
	}
	@Override
	public void run() {
		for(int i=1;i<6;i++) {
			ac.save(1);//1만원씩 저축
		}
	}
}

class UserOut extends Thread{
	Account ac;
	public UserOut(Account ac, String name) {
		this.ac=ac;
		this.setName(name);
	}
	@Override
	public void run() {
		Random ran = new Random();
		for(int i=1;i<6;i++) {
			//1~5만원 사이의 값을 랜덤하게 인출
			int val =ran.nextInt(5)+1;
			ac.get(val);
		}
	}
}

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
package day26;

public class AccountTest {
	public static void main(String[] args) {
		Account ac = new Account();
		UserOut user1=new UserOut(ac,"배짱이");
		UserIn user2=new UserIn(ac,"개미");
		user1.start();
		user2.start();
	}
}

wait(), notify(), notifyall()
동기화 블럭에서만 수행되는 메소드

wait()
wait()가 호출되면 스레드는 수행 권한을 포기하고 waiting pool에 들어가 대기한다.
이 때 모니터 락(lock)을 반납하고 대기 상태로 들어간다.

notify(), notifyAll()
/*notify()가 호출되면 Waiting Pool에 대기중인 
  스레드 하나를 깨워 Runnable한 상태로 전환시킨다. 
  notify()는 특정 스레드를 지정하여 깨우는 것이 아니라 웨이트 풀에 있는 스레드 아무거나 
  하나 골라 깨운다  
  반면 notifyAll()은 wati pool에 있는 모든 스레드를 깨운다.*/

DeadLock
두 스레드간의 상호 의존에 기인하는 버그
다중 스레드가 다중 자원에 접근하기 위해 경쟁하는 프로그램에서 DeadLock이 발생할 수 있다.

+ Recent posts