Java多线程之生产者消费者模型

线程间的通讯

wait() 在对象上等待,等待通知(在等待过程中释放对象锁、等待必须在同步块内、这个对象就是同步锁)《让线程进入阻塞状态,将线程放入等待池中》

notify() 通知在这个对象上等待的一个线程,唤醒它,让它不再等下去(必须在同步块内调用,同步锁必须是调用这个方法的对象)《》

notifyAll() 和notify()差不多,区别在于是通知在这个对象上等待的所有线程

 

注意:线程间通讯的几个方法()

 

总结:wait、notify、notifyAll必须是同步代码块中被调用,

 

 

wait() 在对象上等待,等待通知(在等待过程中释放对象锁、等待必须在同步块内、这个对象就是同步锁)

//要在这个线程中等待

public class Wifeextends Thread {

         private Object message;//等待对象,同时也是同步锁

 

         public Wife(Object message) {

                   this.message = message;     //初始化,从外部传入

         }

         public void run(){

                   synchronized (message){//wait动作必须在一个同步块内部,而且对象锁必须是等待的对象

                            System.out.println("开始等待");

                            try {

                                     message.wait();//在对象进行等待,等待过程中释放锁,另一线程的同步块得以执行

                                     System.out.println("收到音讯,结束等待");

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}

public class Husband{

         public static void main(String[] args){

                   Object message  = new Object();  //创建对象

                   Wife t = newWife(message);      //新建线程,传入对象

                   t.start();//启动

                   System.out.println("上京赶考");

                   try {

                            Thread.sleep(5000);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }

                   System.out.println("考上状元");

                   System.out.println("飞鸽传书");

                   synchronized (message){//notify动作必须在同步块内,而且对象锁必须是调用通知的对象

                            message.notify();//通知在这个对象上等待的线程,当这个同步块结束,通知的那个线程的wait就返回并继续执行

                   }

         }

}

 

notify() 通知在这个对象上等待的一个线程,唤醒它,让它不再等下去(必须在同步块内调用,同步锁必须是调用这个方法的对象)

 

notifyAll() 和notify()差不多,区别在于是通知在这个对象上等待的所有线程

public class CowManextends Thread {

         private Object message;

         public CowMan(Object message) {

                   this.message = message;

         }

         public void run(){

                   synchronized (message) {

                            System.out.println("牛郎等待");

                            try {

                                     message.wait();

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                            System.out.println("牛郎去鹊桥");

                   }

         }

}

public class Fairyextends Thread {

         private Object message;

 

         public Fairy(Object message) {

                   this.message = message;

         }

         public void run(){

                   synchronized (message) {

                            System.out.println("织女等待");

                            try {

                                     message.wait();

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                            System.out.println("兴冲冲跑去鹊桥相会");

                   }

         }

}

public static voidmain(String[] args) throws Exception {

                   Object message = newObject();//创建共同使用的信息对象

                   CowMan cowMan = newCowMan(message);//牛郎和织女都等待同一个信息,七月初七到来的信息

                   Fairy fairy = newFairy(message);

                   cowMan.start();

                   fairy.start();

                   for(int i=1;i<=7;i++){

                            System.out.println("七月初"+i);

                            Thread.sleep(1000);

                   }

                   synchronized (message) {

                            message.notifyAll();//通知在这个对象上等待着的所有线程,牛郎和织女

                   }

         }

 

1.1    生产者消费者模式

public class Demo {

 

         publicstatic void main(String[] args) {

 

                   Resouser = new Resouse("苹果");

                   newProduce("生产者", r).start();

                   newConsumer("消费者", r).start();

         }

 

}

 

/**

 * 消费者类

 *

 */

class Consumer extends Thread {

 

         Resouser;

 

         publicConsumer(String name, Resouse r) {

                   super(name);

                   this.r= r;

         }

 

         @Override

         publicvoid run() {

                   //不停拿资源

                   while(true) {

                            r.get();

                   }

         }

}

 

class Produce extends Thread {

 

         Resouser;

 

         publicProduce(String name, Resouse r) {

                   super(name);

                   this.r= r;

         }

 

         @Override

         publicvoid run() {

                   //不停生产

                   while(true) {

                            r.put();

                   }

         }

}

 

class Resouse {

 

         Stringname;

         intid;

         booleanflag; // 记录有没有资源

 

         publicResouse(String name) {

                   this.name= name;

         }

 

         /**

          * 放资源

          */

         publicsynchronized void put() {

 

                   try{

                            if(flag) {

                                     wait();//让线程进入等待状态(阻塞状态的一种),直到被notify()方法唤醒

                            }

                            //生产资源

                            id++;

                            System.out.println(Thread.currentThread().getName()+ "...生产了....."

                                               +name + id);

                            flag= true;

                            //通知消费者

                            notify();

                            Thread.sleep(500);

                   }catch (InterruptedException e) {

                            //TODO Auto-generated catch block

                            e.printStackTrace();

                   }

         }

 

         //【同步方法的实质是同步代码块,同一个类中的不同行为<方法>的同步,是可行的。同步锁是当前对象,

         //即在多线程中同一时间片段中,对象只会调用类中同步的其中一个同步方法】

 

         /**

          * 取资源

          */

         public/*synchronized */void get() {

                   synchronized(this) {//同步锁就是对象监视器,他只会监控同步锁对应的代码块中的代码

                            try{

                                     if(!flag) { // 没有资源就等待生产

                                               wait();

                                     }

                                     System.out.println(Thread.currentThread().getName()

                                                        +"...消费了...." + name + id);

                                     flag= false; // 消费完得告诉生产者没有资源了

                                     //通知生产者

                                     notify();

                                     Thread.sleep(500);

                            }catch (InterruptedException e) {

                                     //TODO Auto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}

 

 

1.2    生产者消费者复合模式

publicclass Demo {

 

         public static void main(String[] args){

 

                   Resouse r = newResouse("苹果");

                   new Produce("生产者1号",r).start();

                   new Consumer("消费者1号",r).start();

                   new Produce("生产者2号", r).start();

                   new Consumer("消费者2号",r).start();

                  

                   new Produce("生产者3号",r).start();

         }

 

}

 

/**

 * 消费者类

 *

 */

classConsumer extends Thread {

 

         Resouse r;

 

         public Consumer(String name, Resouse r){

                   super(name);

                   this.r = r;

         }

 

         @Override

         public void run() {

                   // 不停拿资源

                   while (true) {

                            r.get();

                   }

         }

}

 

classProduce extends Thread {

 

         Resouse r;

 

         public Produce(String name, Resouse r){

                   super(name);

                   this.r = r;

         }

 

         @Override

         public void run() {

                   // 不停生产

                   while (true) {

                            r.put();

                   }

         }

}

 

classResouse {

 

         String name;

         int id;

         boolean flag; // 记录有没有资源

 

         public Resouse(String name) {

                   this.name = name;

         }

 

         /**

          * 放资源

          */

         public synchronized void put() {

 

                   try {

                            while (flag) {

                                     wait();// 让线程进入等待状态(阻塞状态的一种),直到被notify()方法唤醒

                            }

                            // 生产资源

                            id++;

                            System.out.println(Thread.currentThread().getName()+ "...生产了....."

                                               +name + id);

                            flag = true;

                            // 通知消费者

                            notifyAll();

                            Thread.sleep(500);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }

         }

 

         // 【同步方法的实质是同步代码块,同一个类中的不同行为<方法>的同步,是可行的。同步锁是当前对象,

         // 即在多线程中同一时间片段中,对象只会调用类中同步的其中一个同步方法】

 

         /**

          * 取资源

          */

         public/* synchronized */void get() {

                   synchronized (this) {//同步锁就是对象监视器,他只会监控同步锁对应的代码块中的代码

                            try {

                                     while(!flag) { // 没有资源就等待生产

                                               wait();

                                     }

                                     System.out.println(Thread.currentThread().getName()

                                                        +"...消费了...."+ name + id);

                                     flag =false; // 消费完得告诉生产者没有资源了

                                     // 通知生产者

                                     notifyAll();

                                     Thread.sleep(500);

                            } catch(InterruptedException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                   }

         }

}

 

1.3    新的线程同步方法

多生产者多消费者的问题

1、  if语句换成while语句

  可以保证在生产或消费之前都先判断一次资源的情况

2、  notity方法换成notifyAll方法

   可以保证每次都能唤醒对方的线程

在JDK1.5之后,可以使用Lock接口和Condition接口来解决以上问题

1.3.1  Lock接口

         通过Lock接口也可以实现线程的同步处理,并且可以让同步处理变得更加灵活(需要手动实现获取锁和释放锁的操作)

        

         //示例代码

         //创建Lock对象(可以将Lock对象理解为原来的锁对象)

         Locklock = new ReentrantLock();

         lock.lock();// 获取锁

         try{

                   //被同步的代码

         }finally {

                   lock.unlock();// 释放锁

         }

 

1.3.2  Condition接口

         Condition对象将原先在Object类中的监视器方法(wait、notify、notifyAll)抽取出来进行封装,每一个Condition对象都是一个等待池,一个Lock对象可以绑定多个Condition对象,这样一来可以让线程间的通讯操作变得更加灵活。

        

         //创建Condition对象,并和指定的Lock对象绑定

         Lock lock = ...;

         Condition condition = lock.newCondition();

 

线程间通讯的三个方法

         1)await():替代wait方法

         2)signal():替代notify方法

         3)signalAll():替代notifyAll方法

1.3.3  示例1

/*

 * 有5辆火车要过山洞,但确保山洞同时只能有一辆火车通过(过山洞需要1秒),打印输出火车通过的顺序。

 * (过山洞的顺序是不可控的,只要保证同一时间只有一辆火车能通过山洞即可)

 * 提示:使用线程同步,一辆火车就是一个线程

 */

publicclass LockDemo {

 

         public static void main(String[] args){

                   // TODO Auto-generated methodstub

                  newTrain("火车1").start();

                   new Train("火车2").start();

                   new Train("火车3").start();

                   new Train("火车4").start();

                   new Train("火车5").start();

         }

}

 

classTrain extends Thread{

        

         //创建Lock对象

         static Lock lock = new ReentrantLock();

        

         public Train(String name){

                   super(name);

         }

        

         @Override

         public void run() {

                   //获取锁

                   lock.lock();

                   try {

                            System.out.println(getName()+"过山洞.....");

                            Thread.sleep(1000);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }finally{

                            //释放锁

                            lock.unlock();

                   }

         }

}

 

1.3.4  新线程同步复合应用

publicclass Demo {

 

         public static void main(String[] args){

                   // TODO Auto-generated methodstub

                   Resource r = newResource("苹果");

                   new Producer("生产者1号",r).start();

                   new Producer("生产者2号",r).start();

                   new Consumer("消费者1号",r).start();

                   new Consumer("消费者2号",r).start();

                  

                   new Consumer("消费者三号", r).start();

         }

}

 

/*

 * 消费者类

 */

classConsumer extends Thread {

 

         Resource r;

 

         public Consumer(String name, Resourcer) {

                   super(name);

                   this.r = r;

         }

 

         @Override

         public void run() {

                   while (true) {

                            r.get();

                   }

         }

}

 

/*

 * 生产者类

 */

classProducer extends Thread {

         Resource r;

 

         public Producer(String name, Resourcer) {

                   super(name);

                   this.r = r;

         }

 

         @Override

         public void run() {

                   while (true) {

                            r.put();

                   }

         }

}

 

/*

 * 资源类

 */

classResource {

 

         String name;

         int id;

         boolean flag; // 记录有没有资源

 

         // Lock对象,用于替代同步代码块

         Lock lock = new ReentrantLock();

         // 创建两个等待池

         // 生产者线程用的等待池

         Condition producerCon =lock.newCondition();

         // 消费者线程用的等待池

         Condition consumCon =lock.newCondition();

 

         public Resource(String name) {

                   this.name = name;

         }

 

         // 放资源

         public void put() {

                   lock.lock();

                   try {

                            while (flag) {

                                     // 将当前线程(生产者线程放入等待池)

                                     producerCon.await();// 替代了wait方法

                            }

                            // 生产资源

                            id++;

                            System.out.println(Thread.currentThread().getName()+ "...生产了...."

                                               +name + id);

                            flag = true;

                            // 通知消费者消费

                            // 唤醒消费者等待池中的线程

                            consumCon.signal();

                            Thread.sleep(500);

                   } catch (InterruptedExceptione) {

                            // TODO Auto-generatedcatch block

                            e.printStackTrace();

                   } finally {

                            lock.unlock();

                   }

         }

 

         public void get() {

                   lock.lock();

                   try {

                            while (!flag) {

                                     consumCon.await();

                            }

                            // 消费资源

                            System.out.println(Thread.currentThread().getName()+ "....消费了...."

                                               +name + id);

                            flag = false;

                            //通知生产者生产

                            producerCon.signal();

                            Thread.sleep(500);

                   } catch (InterruptedExceptione) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                   }finally{

                            lock.unlock();

                   }

         }

}

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用Java语言实现的生产者消费者模型的示例: ``` import java.util.LinkedList; public class ProducerConsumerExample { public static void main(String[] args) { LinkedList<Integer> queue = new LinkedList<>(); int maxSize = 5; Producer producer = new Producer(queue, maxSize); Consumer consumer = new Consumer(queue); Thread producerThread = new Thread(producer, "Producer"); Thread consumerThread = new Thread(consumer, "Consumer"); producerThread.start(); consumerThread.start(); } } class Producer implements Runnable { private LinkedList<Integer> queue; private int maxSize; public Producer(LinkedList<Integer> queue, int maxSize) { this.queue = queue; this.maxSize = maxSize; } @Override public void run() { while (true) { synchronized (queue) { while (queue.size() == maxSize) { try { System.out.println("队列已满,生产者等待消费..."); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int number = (int) (Math.random() * 100); queue.add(number); System.out.println("生产者生产: " + number); queue.notifyAll(); } } } } class Consumer implements Runnable { private LinkedList<Integer> queue; public Consumer(LinkedList<Integer> queue) { this.queue = queue; } @Override public void run() { while (true) { synchronized (queue) { while (queue.isEmpty()) { try { System.out.println("队列为空,消费者等待生产..."); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int number = queue.removeFirst(); System.out.println("消费者消费: " + number); queue.notifyAll(); } } } } ``` 上述代码实现了一个简单的生产者消费者模型,其中使用了一个线程安全的`LinkedList`队列作为生产者消费者之间的缓冲区。在`Producer`和`Consumer`类中,`run()`方法被覆盖并实现了生产和消费的逻辑。 在生产者线程中,如果队列已满,则生产者线程将进入等待状态。当队列不满时,生产者线程将生成随机数并将其添加到队列中,并通过调用`notifyAll()`方法通知消费者线程可以消费了。在消费者线程中,如果队列为空,则消费者线程将进入等待状态。当队列不为空时,消费者线程将从队列中删除第一个元素,并通过调用`notifyAll()`方法通知生产者线程可以继续生产。 这种实现方式使用`synchronized`关键字确保在对队列进行修改时线程安全。此外,生产者消费者线程之间的通信使用了`wait()`和`notifyAll()`方法,以确保生产者消费者之间的协调。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值