¦b¤¶²ÐThread¤§«e,§ÚÌ¥²¶·¥ý§âProgram©MProcess³o¨âÓÆ[©À§@¤@ÓÂç²M¡C
¥Ñ¤W±ªº´yz¤¤,§Ú̦bÂk¯ÇThreadªº«ÂI¦p¤U
Java¥Hjava.lang.Thread³oÓÃþ§O¨Óªí¥ÜThread¡CClass Thread¦³¨âÓConstructor:
²Ä¤@Ó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.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();
}
}
¦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¤@ÓÂà±bn¨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:
¦]¦¹¦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) {
}
}
}
¤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++; // ·Qnreadªºthread¤S¦h¤F¤@Ó
while (nw != 0) { // ÁÙ¦³write thread¥¿¦bwrite
wait();
}
nr++; // ¥¿¦bŪªºthread¦h¤F¤@Ó
}
public synchronized void startWriting() throws InterruptedException {
nwtotal++; // ·Qn¼gªºthread¤S¦h¤F¤@Ó
while (nrtotal+nw != 0) { // ¥un¦³thread·QnŪ,©Î¬O¦³thread¥¿¦b¼g,§Åý
wait();
}
nw = 1;
}
public synchronized void stopReading() {
nr--; // ¥¿¦bŪªº¤Ö¤@Ó
nrtotal--; // ·QnŪªº¤Ö¤@Ó
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++; // ·Qnreadªºthread¤S¦h¤F¤@Ó
while (nwtotal != 0) { // ÁÙ¦³thread·Qnwrite
wait();
}
nr++; // ¥¿¦bŪªºthread¦h¤F¤@Ó
}
public synchronized void startWriting() throws InterruptedException {
nwtotal++; // ·Qn¼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--; // ·QnŪªº¤Ö¤@Ó
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¦³threadnwrite, ±Nreader³£©ñ¨ì¥Ø«en³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();
}
}