今天研究了一下java多線程,順便寫了一下多線程中的經典問題-----生產者消費者經典問題,參照了網上的各種寫法之後自己寫了一個,如下所示
- <span style="font-size:14px;">/**生產者消費者問題,涉及到幾個類
- * 第一,這個問題本身就是一個類,即主類
- * 第二,既然是生產者、消費者,那麼生產者類和消費者類就是必須的
- * 第三,生產什麼,消費什麼,所以物品類是必須的,這裏是饅頭類
- * 第四,既然是線程,那麼就不是一對一的,也就是說不是生產一個消費一個,既然這樣,多生產的往哪裏放,
- * 現實中就是筐了,在計算機中也就是數據結構,筐在數據結構中最形象的就是棧了,因此還要一個棧類
- */
- package thread;
- public class ProduceConsume {
- public static void main(String[] args) {
- SyncStack ss = new SyncStack();//建造一個裝饅頭的框
- Producer p = new Producer(ss);//新建一個生產者,使之持有框
- Consume c = new Consume(ss);//新建一個消費者,使之持有同一個框
- Thread tp = new Thread(p);//新建一個生產者線程
- Thread tc = new Thread(c);//新建一個消費者線程
- tp.start();//啓動生產者線程
- tc.start();//啓動消費者線程
- }
- }
- //饅頭類
- class SteamBread{
- int id;//饅頭編號
- SteamBread(int id){
- this.id = id;
- }
- public String toString(){
- return "steamBread:"+id;
- }
- }
- //裝饅頭的框,棧結構
- class SyncStack{
- int index = 0;
- SteamBread[] stb = new SteamBread[6];//構造饅頭數組,相當於饅頭筐,容量是6
- //放入框中,相當於入棧
- public synchronized void push(SteamBread sb){
- while(index==stb.length){//筐滿了,即棧滿,
- try {
- this.wait();//讓當前線程等待
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- this.notify();//喚醒在此對象監視器上等待的單個線程,即消費者線程
- stb[index] = sb;
- this.index++;
- }
- //從框中拿出,相當於出棧
- public synchronized SteamBread pop(){
- while(index==0){//筐空了,即棧空
- try {
- this.wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- this.notify();
- this.index--;//push第n個之後,this.index++,使棧頂爲n+1,故return之前要減一
- return stb[index];
- }
- }
- //生產者類,實現了Runnable接口,以便於構造生產者線程
- class Producer implements Runnable{
- SyncStack ss = null;
- Producer(SyncStack ss){
- this.ss = ss;
- }
- @Override
- public void run() {
- // 開始生產饅頭
- for(int i=0;i<20;i++){
- SteamBread stb = new SteamBread(i);
- ss.push(stb);
- System.out.println("生產了"+stb);
- try {
- Thread.sleep(10);//每生產一個饅頭,睡覺10毫秒
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- //消費者類,實現了Runnable接口,以便於構造消費者線程
- class Consume implements Runnable{
- SyncStack ss = null;
- public Consume(SyncStack ss) {
- super();
- this.ss = ss;
- }
- @Override
- public void run() {
- // TODO Auto-generated method stub
- for(int i=0;i<20;i++){//開始消費饅頭
- SteamBread stb = ss.pop();
- System.out.println("消費了"+stb);
- try {
- Thread.sleep(100);//每消費一個饅頭,睡覺100毫秒。即生產多個,消費一個
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }</span>
運行結果: