Program,Process,Thread

¦b¤¶²ÐThread¤§«e,§Ú­Ì¥²¶·¥ý§âProgram©MProcess³o¨â­ÓÆ[©À§@¤@­ÓÂç²M¡C

¥Ñ¤W­±ªº´y­z¤¤,§Ú­Ì¦bÂk¯ÇThreadªº­«ÂI¦p¤U

¦p¦ó²£¥ÍThread

Java¥Hjava.lang.Thread³o­ÓÃþ§O¨Óªí¥ÜThread¡CClass Thread¦³¨â­ÓConstructor:

  1. Thread()
  2. Thread(Runnable)

²Ä¤@­ÓConstrctor¨S¦³°Ñ¼Æ,²Ä¤G­Ó»Ý­n¤@­ÓRunnableª«¥ó·í°Ñ¼Æ¡CRunnable¬O¤@­Óinterface,©w¸q©ójava.lang¤º,¨ä«Å§i¬°

public interface Runnable {
    public void run();
}

¨Ï¥ÎThread()²£¥ÍªºThread,¨ä¶i¤JÂI¬°Thread¸Ìªºrun();¨Ï¥ÎThread(Runnable)²£¥ÍªºThread,¨ä¶i¤JÂI¬°Runnableª«¥ó¸Ìªºrun()¡C·írun()µ²§ô®É,³o­ÓThread¤]´Nµ²§ô¤F;³o©Mmain()µ²§ô¦³¬Û¦Pªº®ÄªG¡C¨ä¥Îªk¥H¤U­±½d¨Ò»¡©ú:

public class ThreadExample1 extends Thread {
    public void run() { // override Thread's run()
        System.out.println("Here is the starting point of Thread.");
        for (;;) { // infinite loop to print message
            System.out.println("User Created Thread");
        }
    }
    public static void main(String[] argv) {
        Thread t = new ThreadExample1(); // ²£¥ÍThreadª«¥ó
        t.start(); // ¶}©l°õ¦æt.run()
        for (;;) {
            System.out.println("Main Thread");
        }
    }
}

¥H¤Wµ{¦¡°õ¦æ«á,¿Ã¹õ¤W·|«ùÄò¦L¥X"User Created Thread"©Î"Main Thread"ªº¦r¼Ë¡C§Q¥ÎRunnableªº¼gªk¦p¤U

public class ThreadExample2 implements Runnable {
    public void run() { // implements Runnable run()
        System.out.println("Here is the starting point of Thread.");
        for (;;) { // infinite loop to print message
            System.out.println("User Created Thread");
        }
    }
    public static void main(String[] argv) {
        Thread t = new Thread(new ThreadExample2()); // ²£¥ÍThreadª«¥ó
        t.start(); // ¶}©l°õ¦æRunnable.run();
        for (;;) {
            System.out.println("Main Thread");
        }
    }
}

ThreadªºÀu¥ýÅv»P¼vÅT¸ê·½ªº¬ÛÃö¤èªk

Thread.setPriority(int)¥i¥H³]©wThreadªºÀu¥ýÅv,¼Æ¦r¶V¤jÀu¥ýÅv¶V°ª¡CThread©w¸q¤F3­Ó¬ÛÃöªºstatic final variable

public static final int MAX_PRIORITY 10
public static final int MIN_PRIORITY 1
public static final int NORM_PRIORITY 5 

­n´£¿ôŪªÌªº¬O,Àu¥ýÅv°ªªºThread¨ä¦û¦³CPUªº¾÷·|¤ñ¸û°ª,¦ýÀu¥ýÅv§Cªº¤]³£·|¦³¾÷·|°õ¦æ¨ì¡C¨ä¥L¦³ÃöThread°õ¦æªº¤èªk¦³:

§A¥i¥H°õ¦æ¤U­±ªºµ{¦¡,¬Ý¬Ýyield()ªº®ÄªG

public class ThreadExample1 extends Thread {
    public void run() { // overwrite Thread's run()
        System.out.println("Here is the starting point of Thread.");
        for (;;) { // infinite loop to print message
            System.out.println("User Created Thread");
            yield();
        }
    }
    public static void main(String[] argv) {
        Thread t = new ThreadExample1(); // ²£¥ÍThreadª«¥ó
        t.start(); // ¶}©l°õ¦æt.run()
        for (;;) {
            System.out.println("Main Thread");
            yield();
        }
    }
}

Æ[¬Ýjoinªº®ÄªG

public class JoinExample extends Thread {
    String myId;
    public JoinExample(String id) {
        myId = id;
    }
    public void run() { // overwrite Thread's run()
	for (int i=0; i < 500; i++) {
            System.out.println(myId+" Thread");
        }
    }
    public static void main(String[] argv) {
        Thread t1 = new JoinExample("T1"); // ²£¥ÍThreadª«¥ó
        Thread t2 = new JoinExample("T2"); // ²£¥ÍThreadª«¥ó
        t1.start(); // ¶}©l°õ¦æt1.run()
        t2.start();
        try {
            t1.join(); // µ¥«Ýt1µ²§ô
            t2.join(); // µ¥«Ýt2µ²§ô
        } catch (InterruptedException e) {}
        for (int i=0;i < 5; i++) {
            System.out.println("Main Thread");
        }
    }
}

Æ[¬Ýsleepªº®ÄªG

public class SleepExample extends Thread {
    String myId;
    public SleepExample(String id) {
        myId = id;
    }
    public void run() { // overwrite Thread's run()
        for (int i=0; i < 500; i++) {
            System.out.println(myId+" Thread");
            try {
                sleep(100);
            } catch (InterruptedException e) {}
        }
    }
    public static void main(String[] argv) {
        Thread t1 = new SleepExample("T1"); // ²£¥ÍThreadª«¥ó
        Thread t2 = new SleepExample("T2"); // ²£¥ÍThreadª«¥ó
        t1.start(); // ¶}©l°õ¦æt1.run()
        t2.start();
    }
}

Critical Section(ÃöÁä®É¨è)ªº«OÅ@±¹¬I

¦pªG³]­pªÌ¨S¦³´£¨Ñ«OÅ@¾÷¨îªº¸Ü,Thread¨ú±o©M¥¢¥hCPU±±¨îÅvªº®É¾÷¬O¥Ñ§@·~¨t²Î¨Ó¨M©w¡C¤]´N¬O»¡Thread¥i¯à¦b°õ¦æ¥ô¦ó¤@­Ó¾÷¾¹«ü¥O®É,³Q§@·~¨t²Î¨ú¨«CPU±±¨îÅv,¨Ã¥æµ¹¥t¤@­ÓThread¡C¥Ñ©ó¬Y¨Ç¯u¹ê¥@¬Éªº°Ê§@¬O¤£¥i¤À³Îªº,¨Ò¦p¸ó¦æÂà±bX¶ê¥ÑA±b¤á¨ìB±b¤á,Âà±b«e«á³o¨â­Ó±b¤áªºÁ`ª÷ÃB¥²¶·¬Û¦P,¦ý¥Hµ{¦¡¨Ó¹ê§@®É,«oµLªk¥Î¤@­Ó«ü¥O´N§¹¦¨,¦pÂà±b¥i¯à­n¼g¦¨¤U­±ªº³o¤@¬qµ{¦¡½X

if (A >= X) {
    A = A - X; // ½Ķ¦¨3­Ó¾÷¾¹«ü¥OLOAD A, SUB X, STORE A
    B = B +X;
}

¦pªG¨â­ÓThread¦P®É­n¦s¨úA,B¨â±b¤á¶i¦æÂà±b,°²³]·íThread one°õ¦æ¨ìSUBX«á³Q¤¤Â_,Threadtwo±µ¤â°õ¦æ§¹¦¨¥t¤@­ÓÂà±b­n¨D,µM«áThreadoneÄ~Äò°õ¦æ¥¼§¹¦¨ªº°Ê§@,½Ð°Ý³o¨â­ÓÂà±b°Ê§@¥¿½T¶Ü?§Ú­Ì¥HA=1000,B=0,¤À§OÂà±b100,200¶ê¨Ó»¡©ú¦¹µ²ªG

    LOAD A // Thread 1, ²{¦bAÁÙ¬O1000
    SUB 100 // Thread 1
    LOAD A // °²³]¦¹®ÉThread 1³Q¤¤Â_,Thread 2±µ¤â, ¦]¬°Thread 1 ÁÙ¨S¦³°õ¦æSTORE A, ©Ò¥HÅܼÆAÁÙ¬O1000
    SUB 200 // Thread 2
    STORE A // Thread 2, A = 800
    LOAD B // Thread 2, B²{¦b¬O0
    ADD 200 // Thread 2
    STORE B // B=200
    STORE A // Thread 1®³¦^±±¨îÅv, A = 900
    LOAD B // Thread 1, B = 200
    ADD 100 // Thread 1
    STORE B // B = 300

§A·|µo²{°õ¦æ§¹¦¨«áA=900,B=300,¤]´N¬O»¡»È¦æ¥­¥Õ·l¥¢¤F200¶ê¡C·íµM¥t¥~ªº°õ¦æ¶¶§Ç¥i¯à³y¦¨¨ä¥L¤£¥¿½Tªºµ²ªG¡C§Ú­Ì§â³o°ÝÃD¦A¾ã²z¤@¤U:

  1. ¼gµ{¦¡®É°²³]«ü¥O·|´`§Ç°õ¦æ
  2. ¬Y¨Ç¤£¥i¤À³Îªº°Ê§@,»Ý­n¥H¦h­Ó¾÷¾¹«ü¥O¨Ó§¹¦¨
  3. Thread°õ¦æ®É¥i¯à¦b¬Y­Ó¾÷¾¹«ü¥O³Q¤¤Â_
  4. ¨â­ÓThread¥i¯à°õ¦æ¦P¤@¬qµ{¦¡½X,¦s¨ú¦P¤@­Ó¸ê®Æµ²ºc
  5. ³o¼Ë´N¯}Ãa¤F²Ä1ÂIªº°²³]

¦]¦¹¦b¼¶¼g¦h°õ¦æºüªºµ{¦¡®É,¥²¶·¯S§O¦Ò¼{³oºØª¬ªp(¤SºÙ¬°race condition)¡CJavaªº¸Ñ¨M¿ìªk¬O,JVM·|¦b¨C­Óª«¥ó¤WÂ\¤@§âÂê(lock),µM«áµ{¦¡³]­pªÌ¥i¥H«Å§i°õ¦æ¬Y¤@¬qµ{¦¡(³q±`¬O¥Î¨Ó¦s¨ú¦@¦P¸ê®Æµ²ºcªºµ{¦¡½X, ¤SºÙ¬°Critical Section)®É,¥²¶·®³¨ì¬Yª«¥óªºÂê¤~¦æ,³o­ÓÂê¦P®É¶¡³Ì¦h¥u¦³¤@­Ó°õ¦æºü¥i¥H¾Ö¦³¥¦¡C

public class Transfer extends Thread {
    public static Object lock = new Object();
    public static int A = 1000;
    public static int B = 0;
    private int amount;
    public Transfer(int x) {
        amount = x;
    }
    public void run() {
        synchronized(lock) { // ¨ú±olock,¦pªG§Oªºthread A¤w¨ú±o,«h¥Ø«e³o­Óthread·|µ¥¨ìthread AÄÀ©ñ¸Ólock
            if (A >= amount) {
                A = A - amount;
                B = B + amount;
            }
        } // Â÷¶}synchronized°Ï¶ô«á,¦¹thread·|¦Û°ÊÄÀ©ñlock
    }
    public static void main(String[] argv) {
        Thread t1 = new Transfer(100);
        Thread t2 = new Transfer(200);
        t1.start();
        t2.start();
    }
}

°£¤Fsynchronized(ref)ªº»yªk¥i¥HÂê©wref«ü¨ìªºª«¥ó¥~,synchronized¤]¥i¥H¥Î¦bobject method«e­±,ªí¥Ü­nÂê©wthisª«¥ó¤~¯à°õ¦æ¸Ó¤èªk¡C¥H¤U¬OQueueµ²ºcªº½d¨Ò

public class Queue {
    private Object[] data;
    private int size;
    private int head;
    private int tail;
    public Queue(int maxLen) {
        data = new Object[maxLen];
    }
    public synchronized Object deQueue() {
        Object tmp = data[head];
        data[head] = null;
        head = (head+1)%data.length;
        size--;
        return tmp;
    }
    public synchronized void enQueue(Object c) {
        data[tail++] = c;
        tail %= data.length;
        size++;
    }
}

ÁöµM¤W­±ªºµ{¦¡¥¿½TµL»~,¦ý¨Ã¥¼¦Ò¼{¸ê·½¤£¨¬®É¸Ó¦p¦ó³B²z¡C¨Ò¦pQueue¤w¸g¨S¦³¸ê®Æ¤F,«oÁÙ·Q®³¥X¨Ó;©Î¬OQueue¸Ì¤w¸g¶ëº¡¤F¸ê®Æ,¨Ï¥ÎªÌ«oÁÙ­n©ñ¶i¥h?§Ú­Ì·íµM¥i¥H¨Ï¥ÎException Handlingªº¾÷¨î:

public class Queue {
    private Object[] data;
    private int size;
    private int head;
    private int tail;
    public Queue(int maxLen) {
        data = new Object[maxLen];
    }
    public synchronized Object deQueue() throws Exception {
        if (size == 0) {
            throw new Exception();
        }
        Object tmp = data[head];
        data[head] = null;
        head = (head+1)%data.length;
        size--;
        return tmp;
    }
    public synchronized void enQueue(Object c) throws Exception {
        if (size >= maxLen) {
            throw new Exception();
        }
        data[tail++] = c;
        tail %= data.length;
        size++;
    }
}

¦ý°²³]§Ú­Ìªº°õ¦æÀô¹Ò¬O,¬Y¨ÇThread±Mªù­t³dŪ¨ú¨Ï¥ÎªÌªº»Ý¨D,¨Ã§â¤u§@©ñ¨ìQueue¸Ì­±,¬Y¨ÇThread«h±Mªù¥ÑQueue¸Ì§ì¨ú¤u§@»Ý¨D°µ¶i¤@¨B³B²z¡C³oºØ¬[ºcªº¦n³B¬O,¥i¥H§âºC³t©Î¤£©w³tªº¿é¤J(¦p³z¹Lºô¸ôŪ¸ê®Æ,³s½u³t«×¥i¯à®t«Ü¦h),©M§Ö³tªº³B²z¤À¶},¥i¨Ï¨t²Îªº¤ÏÀ³³t«×§ó§Ö,§ó¸`¬Ù¸ê·½¡C¨º»ò¥HExceptoin¨Ó³B²zQueueªÅ±¼©ÎÃz±¼ªº±¡ªp¨Ã¤£¦X¾A,¦]¬°¨Ï¥ÎQueueªº¤H¥²¶·³B²z¨Ò¥~ª¬ªp,¨Ã¤£Â_ªº®ø¯ÓCPU¸ê·½:

public class Getter extends Thread {
    Queue q;
    public Getter(Queue q) {
        this.q = q;
    }
    public void run() {
        for (;;) {
            try {
                Object data = q.deQueue();
                // processing
            } catch(Exception e) {
                // if we try to sleep here, user may feel slow response
                // if we do not sleep, CPU will be wasted
            }
        }
    }
}
public class Putter extends Thread {
    Queue q;
    public Putter(Queue q) {
        this.q = q;
    }
    public void run() {
        for (;;) {
            try {
                Object data = null;
                // get user request
                 q.enQueue(data);
            } catch(Exception e) {
                // if we try to sleep here, user may feel slow response
                // if we do not sleep, CPU will be wasted
            }
        }
    }
}
public class Main {
    public static void main(String[] argv) {
        Queue q = new Queue(10);
        Getter r1 = new Getter(q);
        Getter r2 = new Getter(q);
        Putter w1 = new Putter(q);
        Putter w2 = new Putter(q);
        r1.start();
        r2.start();
        w1.start();
        w2.start();
    }
}

¬°¤F¸Ñ¨M³oÃþ¸ê·½¤À°tªº°ÝÃD,Java Object´£¨Ñ¤F¤U­±¤T­Ómethod:

©Ò¿×Runnable Mode¬O«ü¸ÓThreadÀH®É¥i¥Ñ§@·~¨t²Î¤À°tCPU¸ê·½¡CBlocking Modeªí¥Ü¸ÓThread¥¿¦bµ¥«Ý¬Y­Ó¨Æ¥óµo¥Í,§@·~¨t²Î¤£·|Åý³oºØThread¨ú±oCPU¸ê·½¡C«e¤@­ÓQueueªº½d¨Ò´N¥i¥H¼g¦¨:

public class Queue {
    private Object[] data;
    private int size;
    private int head;
    private int tail;
    public Queue(int maxLen) {
        data = new Object[maxLen];
    }
    public synchronized Object deQueue() {
        while (size==0) { // When executing here, Thread must have got lock and be in running mode
            // Let current Thread wait this object(to sleeping mode)
            try {
                wait(); // to sleeping mode, and release all lock
            } catch(Exception ex) {};
        }
        Object tmp = data[head];
        data[head] = null;
        head = (head+1)%data.length;
        if (size==data.length) {
            // wake up all Threads waiting this object
            notifyAll();
        }
        size--;
        return tmp;
    } // release lock
    public synchronized void enQueue(Object c) {
        while (size==data.length) {  // When executing here, Thread must have got lock and be in running mode
            // Let current thread wait this object(to sleeping mode)
            try {
                wait(); // to sleeping mode, and release all lock
            } catch(Exception ex) {};
        }
        data[tail++] = c;
        tail %= data.length;
        size++;
        if (size==1) {
            // wake up all Threads waiting this object
            notifyAll();
        }
    }
}


public class ReaderWriter extends Thread {
    public static final int READER = 1;
    public static final int WRITER = 2;
    private Queue q;
    private int mode;
    public void run() {
        for (int i=0; i < 1000; i++) {
            if (mode==READER) {
                q.deQueue();
            } else if (mode==WRITER) {
                q.enQueue(new Integer(i));
            }
        }
    }
    public ReaderWriter(Queue q, int mode) {
        this.q = q;
        this.mode = mode;
    }
    public static void main(String[] args) {
        Queue q = new Queue(5);
        ReaderWriter r1, r2, w1, w2;
        (w1 = new ReaderWriter(q, WRITER)).start();
        (w2 = new ReaderWriter(q, WRITER)).start();
        (r1 = new ReaderWriter(q, READER)).start();
        (r2 = new ReaderWriter(q, READER)).start();
        try {
            w1.join(); // wait until w1 complete
            w2.join(); // wait until w2 complete
            r1.join(); // wait until r1 complete
            r2.join(); // wait until r2 complete
        } catch(InterruptedException epp) {
        }
    }
}

Multiple Reader-Writer Monitors

¤W¤@¸`ªºQueue¸ê®Æµ²ºc,¤£½×¬OenQueue()©ÎdeQueue()³£·|§ó°Ê¨ìQueueªº¤º®e¡C¦Ó¦b³\¦hÀ³¥Î¸Ì,¸ê®Æµ²ºc¥i¥H¤¹³\¦P®É¦h­ÓŪ¤@­Ó¼g¡C¥»¸`Á|¥X´X­Ó¤£¦Pªº¨Ò¤l,»¡©ú¦h­ÓReader-Writer®Éªº¥i¯à±Æµ{ªk¡C

Single Reader-Writer, ¥u¦P®É¤¹³\¤@­Ó°õ¦æºü¦s¨ú

public class SingleReaderWriter {
    int n; // number of reader and write, 0 or 1
    public synchronized void startReading() throws InterruptedException {
        while (n != 0) {
            wait();
        }
        n = 1;
    }
    public synchronized void stopReading() {
        n = 0;
        notify();
    }
    public synchronized void startWriting() throws InterruptedException {
        while (n != 0) {
            wait();
        }
        n = 1;
    }
    public synchronized void stopWriting() {
        n = 0;
        notify();
    }
}
// ³o¬O¤@­Ó¨Ï¥Î½d¨Ò, µ{¦¡¯à§_¥¿½T°õ¦æ­n¾a©I¥s¥¿½Tªºstart©Mstop
public class WriterThread extends Thread {
    SingleReaderWriter srw;
    public WriterThread(SingleReaderWriter srw) {
        this.srw = srw;
    }
    public void run() {
        startWring();
        // insert real job here
        stopWriting();
    }
}
public class ReaderThread extends Thread {
    SingleReaderWriter srw;
    public ReaderThread(SingleReaderWriter srw) {
        this.srw = srw;
    }
    public void run() {
        startReading();
        // insert real job here
        stopReading();
    }
}
public class Test {
    public static void main(String[] argv) {
        SingleReaderWriter srw = new SingleReaderWriter;
        // create four threads
        (new WriterThread(srw)).start();
        (new WriterThread(srw)).start();
        (new ReaderThread(srw)).start();
        (new ReaderThread(srw)).start();
    }
}

¨ä¥L¥i¯àªºµ¦²¤¹ê§@¦p¤U:

ReaderÀu¥ý:

public class ReadersPreferredMonitor {
    int nr; // The number of threads currently reading, nr > = 0
    int nw; // The number of threads currently writing, 0 or 1
    int nrtotal; // The number of threads either reading or waiting to read, nrtotal > = nr
    int nwtotal; // The number of threads either writing or waiting to write
    public synchronized void startReading() throws InterruptedException {
        nrtotal++; // ·Q­nreadªºthread¤S¦h¤F¤@­Ó
        while (nw != 0) { // ÁÙ¦³write thread¥¿¦bwrite
            wait();
        }
        nr++; // ¥¿¦bŪªºthread¦h¤F¤@­Ó
    }
    public synchronized void startWriting() throws InterruptedException {
        nwtotal++; // ·Q­n¼gªºthread¤S¦h¤F¤@­Ó
        while (nrtotal+nw != 0) { // ¥u­n¦³thread·Q­nŪ,©Î¬O¦³thread¥¿¦b¼g,§Åý
            wait();
        }
        nw = 1;
    }
    public synchronized void stopReading() {
        nr--; // ¥¿¦bŪªº¤Ö¤@­Ó
        nrtotal--; // ·Q­nŪªº¤Ö¤@­Ó
        if (nrtotal == 0) { // ¦pªG¨S¦³­nŪªº,¥s¿ô·Q¼gªº
            notify();
        }
    }
    public synchronized void stopWriting() {
        nw = 0; // ¨S¦³thread¥¿¦b¼g
        nwtotal--; // ·Q¼gªº¤Ö¤@­Ó
        notifyAll(); // ¥s¿ô©Ò¦³·QŪ©M·Q¼gªº
    }
}

WriterÀu¥ý:

public class WritersPreferredMonitor {
    int nr; // The number of threads currently reading, nr > = 0
    int nw; // The number of threads currently writing, 0 or 1
    int nrtotal; // The number of threads either reading or waiting to read, nrtotal > = nr
    int nwtotal; // The number of threads either writing or waiting to write
    public synchronized void startReading() throws InterruptedException {
        nrtotal++; // ·Q­nreadªºthread¤S¦h¤F¤@­Ó
        while (nwtotal != 0) { // ÁÙ¦³thread·Q­nwrite
            wait();
        }
        nr++; // ¥¿¦bŪªºthread¦h¤F¤@­Ó
    }
    public synchronized void startWriting() throws InterruptedException {
        nwtotal++; // ·Q­n¼gªºthread¤S¦h¤F¤@­Ó
        while (nr+nw != 0) { // ¦³thread¥¿¦bŪ,©Î¬O¦³thread¥¿¦b¼g
            wait();
        }
        nw = 1;
    }
    public synchronized void stopReading() {
        nr--; // ¥¿¦bŪªº¤Ö¤@­Ó
        nrtotal--; // ·Q­nŪªº¤Ö¤@­Ó
        if (nr == 0) { // ¦pªG¨S¦³¥¿¦bŪªº,¥s¿ô©Ò¦³ªº(¥]¬A·Q¼gªº)
            notifyAll();
        }
    }
    public synchronized void stopWriting() {
        nw = 0; // ¨S¦³thread¥¿¦b¼g
        nwtotal--; // ·Q¼gªº¤Ö¤@­Ó
        notifyAll(); // ¥s¿ô©Ò¦³·QŪ©M·Q¼gªº
    }
}

Reader©MWriter¥æ¤¬°õ¦æ:

public class AlternatingReadersWritersMonitor {
    int[] nr = new int[2]; // The number of threads currently reading
    int thisBatch; // Index in nr of the batch of readers currently reading(0 or 1)
    int nextBatch = 1; // Index in nr of the batch of readers waitin to read(always 1-thisBatch)
    int nw; // The number of threads currently writing(0 or 1)
    int nwtotal; // The number of threads either writing or waiting to write
    public synchronized void startReading() throws InterruptedException {
        if (nwtotal == 0) { // ¨S¦³thread­nwrite, ±Nreader³£©ñ¨ì¥Ø«e­n³B²zªº³o¤@§å
            nr[thisBatch]++;
        } else {
            nr[nextBatch]++;
            int myBatch = nextBatch;
            while (thisBatch != myBatch) {
                wait();
            }
        }
    }
    public synchronized void stopReading() {
        nr[thisBatch]--;
        if (nr[thisBatch] == 0) { // ¥Ø«e³o§åªºreader³£Åª§¹¤F,§ä¤U¤@­Ówriter
            notifyAll();
        }
    }
    public synchronized void startWriting() throws InterruptedException {
        nwtotal++;
        while (nr[thisBatch]+nw != 0) { // ¥Ø«e³o§åÁÙ¨S§¹,©Î¦³thread¥¿¦b¼g
            wait();
        }
        nw = 1;
    }
    public synchronized void stopWriting() {
        nw = 0;
        nwtotal--;
        int tmp = thisBatch; // ¥æ´«¤U¤@§å­nŪªº
        thisBatch = nextBatch;
        nextBatch = tmp;
        notifyAll();
    }
}

µ¹¸¹¨Ì§Ç°õ¦æ

public class TakeANumberMonitor {
    int nr; // The number of threads currently reading
    int nextNumber; // The number to be taken by the next thread to arrive
    int nowServing; // The number of the thread to be served next
    public synchronized void startReading() throws InterruptedException {
        int myNumber = nextNumber++;
        while (nowServing != myNumber) { // ÁÙ¨S½ü¨ì§Ú
            wait();
        }
        nr++; // ¦h¤F¤@­ÓReader
        nowServing++; // ·Ç³ÆÀˬd¤U¤@­Ó
        notifyAll();
    }
    public synchronized void startWriting() throws InterruptedException {
        int myNumber = nextNumber++;
        while (nowServing != myNumber) { // ÁÙ¨S½ü¨ì§Ú
            wait();
        }
        while (nr >  0) { // ­nµ¥©Ò¦³ªºReaderµ²§ô
            wait();
        }
    }
    public synchronized void stopReading() {
        nr--; // ¤Ö¤F¤@­ÓReader
        if (nr == 0) {
            notifyAll();
        }
    }
    public synchronized void stopWriting() {
        nowServing++; // ·Ç³ÆÀˬd¤U¤@­Ó
        notifyAll();
    }
}