首页 > 代码库 > 【java】生产者——消费者 线程模型

【java】生产者——消费者 线程模型

下面的4个文件体现了多线程的知识,以及线程同步(synchronized)的使用。其PopThread类对应消费者,PushThread类对应生产者,SafeStack对应存放资源的仓库。下面的TestSafeStack创建了1个生产者对象,1个存放资源的仓库对象,2个消费者对象。

消费者类:

技术分享
 1 /* 2  * 通过实现Runnable接口实现线程 3  */ 4 public class PushThread implements Runnable 5 { 6   /* 7    * 创建一个SafeStack类的变量 8    */ 9   private SafeStack s;10   11   public PushThread(){}12   /*13    * 通过有参的构造函数,传入临界资源14    */15   public PushThread(SafeStack s)16   {17     this.s = s;18   }19   20   /**21    * 重写run()方法22    */23   @Override24   public void run()25   {26     int temp = 0;27     28     for(int i=0;i<100;i++)29     {30       /*31        * 产生一个[0,10)的数字,并且保存到temp变量中32        */33       java.util.Random r = new java.util.Random();34       temp = r.nextInt(10);35       //调用临界资源中push方法36       s.push(temp);37       38       /*39        * 调用Thread.sleep()方法,让当前线程休眠0.1秒后再执行40        */41       try {42         Thread.sleep(100);43       }44       catch(InterruptedException e){45           e.printStackTrace();46       }47     }48   }  49 }
PushThread类

消费者类:

技术分享
 1 public class PopThread extends Thread { 2     private SafeStack s; 3  4     public PopThread() { 5     } 6  7     public PopThread(SafeStack s) { 8         this.s = s; 9     }10 11     public void run() {12         for (int i = 0; i < 100; i++) {13             int temp = s.pop();14             System.out.println("->" + temp + "<-");15             try {16                 Thread.sleep(100);17             } catch (InterruptedException e) {18                 e.printStackTrace();19             }20         }21     }22 }
PopThread类

仓库类:

技术分享
public class SafeStack{  private int top = 0;//下标  /*   * 用于存储产生的随机数整数   */  private int[] values = new int[10];//数组  /*   * 压栈和出栈的标志,通过dataAvailable变量控制push()方法和pop()方法中线程的等待。   * dataAvailable的值默认是false,最开始让pop()方法中线程中等待。   */  private boolean dataAvailable = false;    public void push(int n)//压栈方法   {    /*     * 使用synchronized关键字实现同步锁     */    synchronized(this)    {      /*       * 如果dataAvailable的值是true,则让线程线程进入等待。       */      while(dataAvailable)//循环锁      {//while是循环判断,if是单次判断          try        {//必须在synchronized语句块内调用wait            wait();//等待,交钥匙后进等待池        }          catch(InterruptedException e)        {            e.printStackTrace();        }              }      values[top] = n;      System.out.println("压入数字"+n+"步骤1完成");      top++;//入栈完成      if(top>=values.length){//当values数组满后才改变状态          dataAvailable = true;//状态变为出栈          notifyAll();//从等待池中唤醒所有线程          System.out.println("压入数字完成");      }    }  //同步结束  }  public synchronized int pop()   {      while(!dataAvailable)      {        try        {          wait();        }          catch(InterruptedException e)        {          e.printStackTrace();        }              }        System.out.print("弹出");      top--;//每一次取出一个数字      int test=values[top];      if(top<=0){//当数组中的所有数据都弹出完后才改变状态          dataAvailable = false;          //唤醒正在等待压入数据的线程          notifyAll();      }      return test;    }  }
SafeStack类

测试类:

技术分享
 1 public class TestSafeStack{ 2     public static void main(String[] args){ 3         /* 4          * 只创建一个临界资源 5          */ 6         SafeStack s = new SafeStack(); 7          8         PushThread r1 = new PushThread(s); 9         PopThread r2 = new PopThread(s);10         PopThread r3 = new PopThread(s);11         12         /*13          * 创建三个线程,一个PushThread和两个PopThread线程14          */15         Thread t1 = new Thread(r1);16         Thread t2 = new Thread(r2);    17         Thread t3 = new Thread(r3);18         19         t1.start();20         t2.start();21         t3.start();22     }    23 }
TestSafeStack类

同步需要使用关键字synchronized,语法格式为:

synchronized(对象引用){//需要被同步的代码}

如果需要同步整个run,则只需要在run方法上加上synchronized关键字即可

public synchronized void run() {...}

创建多线程也可以通过匿名内部类构造器来实现,构造器适合于创建对象的资源只使用一次。比如:

        new Thread(){//继承的构造器            @Override            public void run(){                for(int i=0;i<10;i++){                    System.out.println("<"+i+">");                    try{                        Thread.sleep(1000);                    }catch(InterruptedException e){                        e.printStackTrace();                    }                }            }        }.start();        Thread td=new Thread(new Runnable(){//实现接口的构造器            @Override            public void run() {                for(int j=0;j<10;j++){                    System.out.println(">"+j+"<");                    try{                      Thread.sleep(2000);                    }catch(InterruptedException e){                        e.printStackTrace();                    }                }            }        });                td.start();//其中线程

 

当时上面的例子就不可以通过构造器来实现,因为在TestSafeStack.java中的创建的临界资源s

SafeStack s = new SafeStack()

被用于创建三个对象,就是:

        PushThread r1 = new PushThread(s);        PopThread r2 = new PopThread(s);        PopThread r3 = new PopThread(s);

所以涉及到临界资源的问题都不可以通过构造器来实现。

【java】生产者——消费者 线程模型