一個JAVA多線程的實例
寫出一組模擬生產者/消費者的協作程序
其中包括一個WoTou.java,代表消息
一個MsgQueue.java,爲一個隊列,提供put(Message msg)方法和get()方法
一個Produer.java,爲生產者線程,在其run方法中每隔1秒產生一個Message對像並放入MsgQueue隊列
一個Consumer.java爲消費者線程,在其run方法中不斷從MsgQueue隊列中獲取Message對像,並顯示在屏幕上
一個TestMain.java,在其main方法中,啓動2個Produer線程和2個消費者線程.
要求:
對於MsgQueue.java,隊列的長度爲10,當消息超過10個時,put()方法需要阻塞:當消息隊列爲空時,
get()方法需要阻塞。
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p1= new Producer(ss,"p1");
Consumer c1= new Consumer(ss,"c1");
Producer p2= new Producer(ss,"p2");
Consumer c2= new Consumer(ss,"c2");
}
}
class WoTou<T> {
int id;
WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou : " + id;
}
}
class SyncStack {
int index = 0;
WoTou[] arrWT = new WoTou[6];
public void push(WoTou wt) {
while(index == arrWT.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
arrWT[index] = wt;
index ++;
}
public WoTou pop() {
while(index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
index--;
return arrWT[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
String a;
Producer(SyncStack ss,String a) {
this.ss = ss;
this.a= a;
Thread t=new Thread(this,a);
t.start();
}
public void run() {
for(int i=0; i<10; i++) {
synchronized(ss){
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println(a+" 生產了:" + wt);}
try {
Thread.sleep((int)(Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
String a;
Thread t;
Consumer(SyncStack ss,String a) {
this.ss = ss;
this.a= a;
t=new Thread(this,a);
t.start();
}
public void run() {
for(int i=0; i<10; i++) {
synchronized(ss){
WoTou wt = ss.pop();
System.out.println(a+" 消費了: " + wt);}
try {
Thread.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
p1 生產了:WoTou : 0
p2 生產了:WoTou : 0
p3 生產了:WoTou : 0
c1 消費了: WoTou : 0
c1 消費了: WoTou : 0
p3 生產了:WoTou : 1
c1 消費了: WoTou : 1
c1 消費了: WoTou : 0
p3 生產了:WoTou : 2
p1 生產了:WoTou : 1
c1 消費了: WoTou : 1
p2 生產了:WoTou : 1
p2 生產了:WoTou : 2
c1 消費了: WoTou : 2
p2 生產了:WoTou : 3
p3 生產了:WoTou : 3
c1 消費了: WoTou : 3
p3 生產了:WoTou : 4
p2 生產了:WoTou : 4
c1 消費了: WoTou : 4
c1 消費了: WoTou : 4
p1 生產了:WoTou : 2
c1 消費了: WoTou : 2
p2 生產了:WoTou : 5
p3 生產了:WoTou : 5
p2 生產了:WoTou : 6
棧裏有6個
作爲多線程交互一的一個重要應用,定義用戶輸入和輸出的列隊類或者堆棧類一定要看成一個整體放進同步語句塊裏面,不能簡單的分別調用輸入同步方法或者輸出同步方法。下面的程序就有問題 下面這個是一個教程例子,但是結果不對。究其原因實際上是因爲列隊類或者堆棧類是一個可變類 ,這種可變類要是有參數傳遞給某些不可變類時,可變類的構造方法必須也設置成爲同步方法,不然就會出錯。
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou {
int id;
WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou : " + id;
}
}
class SyncStack {
int index = 0;
WoTou[] arrWT = new WoTou[6];
public synchronized void push(WoTou wt) {
while(index == arrWT.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
arrWT[index] = wt;
index ++;
}
public synchronized WoTou pop() {
while(index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();
index--;
return arrWT[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
Producer(SyncStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生產了:" + wt);
try {
Thread.sleep((int)(Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
Consumer(SyncStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou wt = ss.pop();
System.out.println("消費了: " + wt);
try {
Thread.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
運行後的結果棧裏有7個 爲什麼會這樣呢?你思考一下