【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   @Override
24   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);

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

时间: 2024-10-17 01:21:08

【java】生产者——消费者 线程模型的相关文章

多线程--生产者/消费者线程模型

//程序演进1 //thread loop,忙等Busy wait //不断的检查是不是该做什么事情了:为了减少CPU占用,sleep睡眠一会 //while (1) //{ // do_something(); // sleep(time); //} //程序演进2 //while (1) //{ // read_form_intput(); // do_something(); //} //程序员演进3,消息模型 //while (waitForMsg) //{ // if (isQuitM

python 生产者消费者线程模型

python 多线程生产者消费者模型: 一个生产者多个消费者 The Queue module implements multi-producer, multi-consumer queues. It is especially useful in threaded programming when information must be exchanged safely between multiple threads. The Queue class in this module imple

java生产者消费者模型

import java.util.Queue;import java.util.concurrent.LinkedBlockingQueue; public class Consumer extends Thread {    private String product;    private Queue<String> storeHouse = new LinkedBlockingQueue<String>();        public Consumer(){      

java 生产者消费者问题

引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品.互相等待,从而发生死锁. 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品.解决生产者/

java 生产者消费者问题 并发问题的解决(转)

引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品.互相等待,从而发生死锁. 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品.解决生产者/

基于Java 生产者消费者模式(详细分析)

本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模式(单面包)6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模

wait和notify实现的生产者消费者线程交互

public class ProductTest { public static void main(String args[]) { Repertory repertory=new Repertory(); new Thread(new Producer(repertory)).start(); new Thread(new Consumer(repertory)).start(); } } class Repertory{ private int product=0; public sync

使用Win32 API实现生产者消费者线程同步

使用win32 API创建线程,创建信号量用于线程的同步 创建信号量 语法例如以下 HANDLE semophore; semophore = CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); CreateSemophore函数的原型例如以下: HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreA

java生产者-消费者

(一).问题的引出 有一个数据存储空间,划分为两部分,一部分用于存储人的姓名,另一部分用于存储人的性别; 我们的应用包含两个线程,一个线程不停向数据存储空间添加数据(生产者),另一个线程从数据空间取出数据(消费者); 因为线程的不确定性,存在于以下两种情况: 1.若生产者线程刚向存储空间添加了人的姓名还没添加人的性别,CPU就切换到了消费者线程,消费者线程把姓名和上一个人的性别联系到一起: 2.生产者放了若干数据,消费者才开始取数据,或者是消费者取完一个数据,还没等到生产者放入新的数据,又重复的