Java线程通信中关于生产者与消费者案例分析

作者:威斯布鲁克.猩猩 时间:2022-01-18 10:49:25 

相关方法:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
说明:
1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。
否则,会出现IllegalMonitorStateException异常
3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

线程通信的例子:使用两个线程打印1-100.线程1,线程2 交替打印


class Number implements Runnable{
   private int number = 1;
   @Override
   public void run() {
       while(true){
           synchronized (this) {
               notify();
               if(number <= 100){
                   try {
                       Thread.sleep(10);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName() + ":" + number);
                   number++;
                   try {
                       //使得调用如下wait()方法的线程进入阻塞状态
                       wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }else{
                   break;
               }
           }
       }
   }
}
public class CommunicationTest {
   public static void main(String[] args) {
       Number number = new Number();
       Thread t1 = new Thread(number);
       Thread t2 = new Thread(number);
       t1.setName("线程1");
       t2.setName("线程2");
       t1.start();
       t2.start();
   }
}

经典例题:生产者/消费者问题

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产,如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

这里可能出现两个问题:

>生产者比消费者快时,消费者会漏掉一些数据没有取到。

>消费者比生产者块时,消费者会取相同的数据。

分析:

  1. 是否是多线程问题?是,生产者线程,消费者线程

  2. 是否有共享数据?有,店员(或产品)

  3. 如何解决线程安全问题?同步机制,有三种方法

  4. 是否涉及线程的通信?是


class Clerk{
   private int productCount = 0;
   //生产产品
   public synchronized void produceProduct() {
       if(productCount < 20){
           productCount++;
           System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品");
           notify();
       }else{
           try {
               wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
   }
   //消费产品
   public synchronized void consumeProduct() {
       if(productCount > 0){
           System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品");
           productCount--;
           notify();
       }else{
           try {
               wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
   }
}
class Producer extends Thread{//生产者
   private Clerk clerk;
   public Producer(Clerk clerk){
       this.clerk = clerk;
   }
   @Override
   public void run() {
       System.out.println(getName() + ":开始生产产品.....");
       while(true){
           try {
               sleep(10);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           clerk.produceProduct();
       }
   }
}
class Consumer extends Thread{//消费者
   private Clerk clerk;
   public Consumer(Clerk clerk){
       this.clerk = clerk;
   }
   @Override
   public void run() {
       System.out.println(getName() + ":开始消费产品.....");
       while(true){
           try {
               sleep(10);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           clerk.consumeProduct();
       }
   }
}
public class ProductTest {
   public static void main(String[] args) {
       Clerk clerk = new Clerk();
       Producer p1 = new Producer(clerk);
       p1.setName("生产者1");
       Consumer c1 = new Consumer(clerk);
       c1.setName("消费者1");
       Consumer c2 = new Consumer(clerk);
       c2.setName("消费者2");
       p1.start();
       c1.start();
       c2.start();
   }
}

sleep()和wait()的异同?

1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:

1)两个方法声明的位置不同,Thread类中声明sleep(),Object类中声明wait()

2)调用的要求不同:sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块或同步方 法中

3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放 锁,wait()会释放锁

来源:https://blog.csdn.net/weixin_49329785/article/details/119454916

标签:Java,线程通信,多线程
0
投稿

猜你喜欢

  • Java Socket编程(四) 重复和并发服务器

    2022-06-29 07:07:06
  • Java线程池ThreadPoolExecutor源码深入分析

    2023-11-09 19:49:36
  • Mybatis之association和collection用法

    2021-10-13 10:09:10
  • Java命名规范

    2022-10-03 00:06:59
  • Spring学习通过AspectJ注解方式实现AOP操作

    2023-09-22 22:09:44
  • Java常用的八种排序算法及代码实现+图解

    2022-04-09 13:30:06
  • Java实现在线聊天功能

    2021-10-18 22:16:23
  • Default Methods实例解析

    2023-05-18 19:28:01
  • 如何解决Java多线程死锁问题

    2022-08-11 15:51:02
  • Java中Synchronized的用法解析

    2023-07-28 22:40:51
  • Java中两种基本的输入方式小结

    2023-02-06 18:37:24
  • SpringBoot自动配置深入探究实现原理

    2023-08-06 09:59:58
  • MyBatis3源码解析之如何获取数据源详解

    2023-12-06 02:23:08
  • maven环境变量配置讲解

    2023-11-29 12:35:51
  • java控制台输出百分比进度条示例

    2023-08-21 22:58:20
  • java网络编程基础知识介绍

    2023-01-10 20:37:44
  • Java利用Easyexcel导出excel表格的示例代码

    2023-05-30 23:36:04
  • kill命令在Java应用中使用的注意事项小结

    2023-11-11 13:01:55
  • 关于MyBatis plus条件构造器的逐条详解

    2021-10-06 07:31:51
  • SpringBoot整合Pulsar的实现示例

    2021-10-09 17:39:35
  • asp之家 软件编程 m.aspxhome.com