
모니터는 세마포 이후에 등장한 프로세스 동기화 도구이며 세마포보다 더 고수준의 개념이다.

notify() : 조건 동기 큐에 있는 스레드 한개를 깨운다.notifyAll() : 조건 동기 큐에 있는 모든 스레드를 깨운다.wait() : 현재 실행중인 스레드를 조건 동기 큐에 삽입한다.자바의 모든 객체는 모니터가 될 수 있다.
class C {
private value, ...;
{
...
}
{
...
}
{
...
}
}
자바에서 상호 배타 큐는 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은 세마포의 방식과 유사하다.
NoteMesa semantics: Java 모니터는 Mesa semantics를 따른다.
notify()를 받은 스레드는 즉시 실행되지 않고 준비 큐(ready queue)에 들어가며, 다른 스레드가 먼저 실행될 수 있다. 따라서 깨어난 뒤에도 조건이 여전히 참인지 재확인해야 하므로if대신while을 사용한다. 이와 달리 Hoare semantics는notify()를 호출한 스레드가 즉시 CPU를 양도하고 깨워진 스레드가 바로 실행되지만, Java는 이를 보장하지 않는다.
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;
count++;
notify();
}
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 philosophers & 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();
}
}