YJ의 새벽
JAVA ( 쓰레드의 동기화 ) 본문
- 동기화 ( 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