YJ의 새벽

JAVA ( 쓰레드의 동기화 ) 본문

SelfStudy/JAVA

JAVA ( 쓰레드의 동기화 )

YJDawn 2023. 2. 8. 15:13

 

  • 동기화 ( synchronization )

 

--한 쓰레드가 진행중인 작업을 다른 쓰레드가 간섭하지 못하게 막는것.

--동기화하려면 간섭받지 않아야 하는 문장들을 "임계영역"으로 설정.

   --임계영역이란 : 중단한 작업을 다른쓰레드가 들어오지 못하는 영역.

--임계영역은 락(lock)을 얻은 단 하나의 쓰레드만 출입 가능. ( 객체 1개에 락1개 )

 

 

 

--synchronized 를 이용한 동기화. 2가지.

 

-- 임계영역은 한번에 한개의 쓰레드만 들어갈수있기에

    갯수를 최소화하는게 좋다.  ( 메서드보다 특정한영역을 지정하는게 좋음 )

class Account {
	private int balance = 1000;           //private 으로해야 동기화의 의미가있다.

	public synchronized int getBalance() {          // 동기화 적용,
		return balance;
	}

	public synchronized void withdraw(int money) {      // 동기화 적용, 
		if (balance >= money) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			balance -= money;
		}
	}
} // end of Account

class RunnableEx implements Runnable{
	
	Account account = new Account();
	
	public void run() {
		while(account.getBalance() > 0) {
			int money = (int)(Math.random()*3+1)*100;    //출금금액 100~300 랜덤
			account.withdraw(money);
			System.out.println("balance: "+account.getBalance());
		}
	}
} // end of RunnableEx 


public class Example {
	public static void main(String[] args) {

		RunnableEx thread = new RunnableEx();
		new Thread(thread).start();
		new Thread(thread).start();
	}
}

동기화를 하지않았을때. 음수출력
동기화했을때. 음수출력하지않음

 

 

 

 

  • wait()  ,  notify() 

--동기화의 효율을 높이기위해 wait , notify 사용.

wait :  기다림

notify :  통보, 알려주기

 

 

 

import java.util.ArrayList;

class Customer implements Runnable {
	private Table table;
	private String food;

	Customer(Table table, String food) {
		this.table = table;
		this.food = food;
	}

	public void run() {
		while (true) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
			}
			String name = Thread.currentThread().getName();
			table.remove(food);                             // Customer이 음식을 먹는 쓰레드.
			System.out.println(name + " ate a " + food);
		}
	}// end of run()
} // end of Customer class

class Cook implements Runnable {
	private Table table;

	Cook(Table table) {
		this.table = table;
	}

	public void run() {
		while (true) {
			int idx = (int) (Math.random() * table.dishNum());
			table.add(table.dishNames[idx]);                  // Cook 이 음식을 채우는 쓰레드
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}
}// end of Cook class

class Table {
	String[] dishNames = { "donut", "donut", "burger" }; // donut 의 확률을 높인다
	final int MAX_FOOD = 6;
	private ArrayList<String> dishes = new ArrayList();

	public synchronized void add(String dish) {
		while (dishes.size() >= MAX_FOOD) {
			String name = Thread.currentThread().getName();
			System.out.println(name + " is waiting");
			try {
				wait();                  //  Cook 쓰레드를 wait .    ( MAX_FOOD가 6일때 )
				Thread.sleep(500);
			} catch (InterruptedException e) {
			}
		}
		dishes.add(dish);
		notify();                      // 기다리고있는 Customer 을 깨움  ( 6 다찼으니 먹어라 )
		System.out.println("Dishes: " + dishes.toString());
	} // end of add(String dish)

	public void remove(String dishName) {
		synchronized (this) {
			String name = Thread.currentThread().getName();

			while (dishes.size() == 0) {
				System.out.println(name + "is waiting");
				try {
					wait();                           // 원하는음식이 없으니 customer 을 기다리게함
					Thread.sleep(500);
				} catch (InterruptedException e) {
				}
			}
			while (true) {
				for( int i=0; i < dishes.size(); i++) {
					if(dishName.equals(dishes.get(i))) {
						dishes.remove(i);
						notify();                         // 자고있는 Cook 을 깨움 (음식만들어라)
						return;
					}
				} //end of for
				try {
					System.out.println(name+" is waiting");
					wait();                   // 원하는음식이 없는 Custmer 쓰레드를 기다리게
					Thread.sleep(500);
				}catch(InterruptedException e) {}
			}
		}
	}
	public int dishNum() {
		return dishNames.length;
	}
}   //end of Table class

public class Example {
	public static void main(String[] args) {

		Table table = new Table();
		
		new Thread(new Cook(table), "COOK").start();
		new Thread(new Customer(table,"donut"),"CUST1").start();
		new Thread(new Customer(table,"burger"),"CUST2").start();
		
		try {
			Thread.sleep(2000);            // 2초동안 진행.
		}catch(InterruptedException e) {}
		
		System.exit(0);	
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

'SelfStudy > JAVA' 카테고리의 다른 글

JAVA ( 함수형인터페이스 )  (0) 2023.02.09
JAVA ( 람다식 )  (0) 2023.02.09
JAVA (쓰레드의 메서드)  (0) 2023.02.07
JAVA ( 데몬 쓰레드 )  (0) 2023.02.07
JAVA (쓰레드 thread)  (0) 2023.02.07
Comments