모니터는 세마포 이후에 등장한 프로세스 동기화 도구이며 세마포보다 더 고수준의 개념이다.
notify()
: 조건 동기 큐에 있는 쓰레드 한개를 깨운다.notifyAll()
: 조건 동기 큐에 있는 모든 쓰레드를 깨운다.wait()
: 현재 실행중인 쓰레드를 조건 동기 큐에 삽입한다.자바의 모든 객체는 모니터가 될 수 있다.
class C {
private int value, ...;
synchronized void f() {
...
}
synchronized void g() {
...
}
void h() {
...
}
}
자바에서 상호 배타 큐는 synchronized
키워드를 사용하여 지정할 수 있다.
조건 동기 큐는 wait()
, notify()
, notifyAll()
메소드를 사용한다.
synchronized
키워드로 선언된 f()
, g()
함수는 상호 배타 함수이며, 똑같은 임계 구역을 갖는다는 의미를 갖고 있다. 따라서 f()
함수 또는 g()
함수가 어떤 쓰레드를 실행중이라면, 다른 쓰레드들은 이 함수에 접근할 수 없다.
h()
함수는 일반 함수로써, 여러 쓰레드가 동시에 접근이 가능하다.
class Test {
public static void main(String[] args)
throws InterruptedException {
BankAccount b = new
BankAccount();
Parent p = new Parent(b);
Child c = new Child(b);
p.start();
c.start();
p.join();
c.join();
System.out.println( "\nbalance = " + b.getBalance());
}
}
class BankAccount {
int balance;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
}
synchronized void withdraw(int amt) {
int temp = balance - amt;
System.out.print("-");
balance = temp;
}
int getBalance() {
return balance;
}
}
class Parent extends Thread {
BankAccount b;
Parent(BankAccount b) {
this.b = b;
}
public void run() {
for (int i=0; i<100; i++)
b.deposit(1000);
}
}
class Child extends Thread {
BankAccount b;
Child(BankAccount b) {
this.b = b;
}
public void run() {
for (int i=0; i<100; i++)
b.withdraw(1000);
}
}
+++++++++++++++++++++++------------------------------------------+++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
----------------------------------------
balance = 0
synchronized
키워드를 통해 모니터를 선언하여 상호 배제가 이루어졌다. 세마포보다 코드가 더 간결해진 것을 확인할 수 있다.
모니터에서의 Ordering은 세마포의 방식과 유사하다.
2개의 프로세스 P1, P2가 있을 때 다음과 같이 실행할 수 있다.
P1 | P2 |
---|---|
wait() | |
S1 | S2 |
notify() |
class BankAccount {
int balance;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
notify();
}
synchronized void withdraw(int amt) {
while (balance <= 0)
try {
wait();
} catch (InterruptedException e) {}
int temp = balance - amt;
System.out.print("-");
balance = temp;
}
int getBalance() {
return balance;
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++------------------------------------------------------------
----------------------------------------
balance = 0
class BankAccount {
int balance;
synchronized void deposit(int amt) {
while (balance == 0)
try {
wait();
} catch (InterruptedException e) {}
int temp = balance + amt;
System.out.print("+");
balance = temp;
}
synchronized void withdraw(int amt) {
int temp = balance - amt;
System.out.print("-");
balance = temp;
notify();
}
int getBalance() {
return balance;
}
}
--------------------------------------------------------------------------------
--------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++
balance = 0
class BankAccount {
int balance;
boolean p_turn = true;
synchronized void deposit(int amt) {
int temp = balance + amt;
System.out.print("+");
balance = temp;
notify();
p_turn = false;
try {
wait();
} catch (InterruptedException e) {}
}
synchronized void withdraw(int amt) {
while (p_turn)
try {
wait();
} catch (InterruptedException e) {}
int temp = balance - amt;
System.out.print("-");
balance = temp;
notify();
p_turn = true;
}
int getBalance() {
return balance;
}
}
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
balance = 0
class Buffer {
int[] buf;
int size, count, in, out;
Buffer(int size) {
buf = new int[size];
this.size = size;
count = in = out = 0;
}
synchronized void insert(int item) {
while (count == size)
try {
wait();
} catch (InterruptedException e) {}
buf[in] = item;
in = (in+1)%size;
notify();
count++;
}
synchronized int remove() {
while (count == 0)
try {
wait();
} catch (InterruptedException e) {}
int item = buf[out];
out = (out+1)%size;
count--;
notify();
return item;
}
}
class Producer extends Thread {
Buffer b;
int N;
Producer(Buffer b, int N) {
this.b = b; this.N = N;
}
public void run() {
for (int i=0; i<N; i++)
b.insert(i);
}
}
class Consumer extends Thread {
Buffer b;
int N;
Consumer(Buffer b, int N) {
this.b = b; this.N = N;
}
public void run() {
int item;
for (int i=0; i<N; i++)
item = b.remove();
}
}
class Test {
public static void main(String[] arg) {
Buffer b = new Buffer(100);
Producer p = new Producer(b, 10000);
Consumer c = new Consumer(b, 10000);
p.start();
c.start();
try {
p.join();
c.join();
} catch (InterruptedException e) {}
System.out.println("Number of items in the buf is " + b.count);
}
class Philosopher extends Thread {
int id; // philosopher id
Chopstick lstick, rstick;
Philosopher(int id, Chopstick lstick, Chopstick rstick) {
this.id = id;
this.lstick = lstick;
this.rstick = rstick;
}
public void run() {
try {
while (true) {
lstick.acquire();
rstick.acquire();
eating();
lstick.release();
rstick.release();
thinking();
}
}catch (InterruptedException e) { }
}
void eating() {
System.out.println("[" + id + "] eating");
}
void thinking() {
System.out.println("[" + id + "] thinking");
}
}
class Chopstick {
private boolean inUse = false;
synchronized void acquire() throws InterruptedException {
while (inUse)
wait();
inUse = true;
}
synchronized void release() {
inUse = false;
notify();
}
}
class Test {
static final int num = 5; // number of philosphers & chopsticks
public static void main(String[] args) {
int i;
/* chopsticks */
Chopstick[] stick = new Chopstick[num];
for (i=0; i<num; i++)
stick[i] = new Chopstick();
/* philosophers */
Philosopher[] phil = new Philosopher[num];
for (i=0; i<num; i++)
phil[i] = new Philosopher(i, stick[i], stick[(i+1)%num]);
/* let philosophers eat and think */
for (i=0; i<num; i++)
phil[i].start();
}
}