zoukankan      html  css  js  c++  java
  • 线程通信问题--生产者和消费者问题

    一、问题引入:首先实现一个线程通信的实例,使用两个线程交替打印输出100以内的数字。

    代码实现如下:

     1 package com.baozi.exer;
     2 
     3 public class CommunicationTest {
     4     public static void main(String[] args) {
     5         Number number = new Number();
     6         Thread t1 = new Thread(number);
     7         Thread t2 = new Thread(number);
     8         t1.setName("线程1");
     9         t2.setName("线程2");
    10         t1.start();
    11         t2.start();
    12     }
    13 
    14 }
    15 
    16 class Number implements Runnable {
    17     private int number = 1;
    18 
    19     @Override
    20     public void run() {
    21         while (true) {
    22             synchronized (this) {
    23                 notify();
    24                 if (number <= 100) {
    25                     try {
    26                         Thread.sleep(100);
    27                     } catch (InterruptedException e) {
    28                         e.printStackTrace();
    29                     }
    30                     System.out.println(Thread.currentThread().getName() + ":" + number);
    31                     number++;
    32                     try {
    33                         wait();
    34                     } catch (InterruptedException e) {
    35                         e.printStackTrace();
    36                     }
    37                 } else {
    38                     break;
    39                 }
    40             }
    41         }
    42     }
    43 }

    wait()、notify()、notifyAll()三个方法的介绍:

    • wait():某个对象调用wait()方法能让当前线程阻塞,并且当前线程还会释放所拥有的锁
    • 调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
    • 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;

    备注:wait()、notify()、notifyAll()三个方法都是定义在同步代码块或者是同步方法中的,并且都是同步代码块或者同步方法的同步监视器进行调用这些方法。

    二、为什么这三个方法都是定义在Object类中,而不是定义在Thread类中?

      这三个方法都是定义在Object类中,因为我们知道,这三个方法都是存在于同步代码块或者同步方法中的,而且必须是该代码块的同步监视器进行调用这些方法,那么因为同步监视器是任何一个类的对象都可以充当,如果要保证任何一个类的对象都有这三个方法并且能进行调用,就只能把这三个方法方法所有类的父类--Object类中。

    三、Sleep()方法和Wait()方法有什么异同?

    相同点:一旦执行这两个方法,都会使当前线程进入阻塞状态

    不同点:

    • 两个方法声明的位置不同:sleep()方法是在Thread类中声明为一个静态方法,而wait()方法是定义在Object类中
    • 两个方法的使用位置不同:sleep可以在任何位置使用,但是wait()方法只能在同步代码块或者是同步方法中使用
    • sleep()方法执行完之后虽然会使当前线程进入阻塞状态,但是并不会使当前线程释放所拥有的锁,但是wait()方法不但会让当前的线程进入阻塞状态,还会是当前的线程释放拥有的锁。

    四、经典的线程通信问题:生产者和消费者问题

      1 package com.baozi.java2;
      2 
      3 /**
      4  * 线程通信的应用:生产者消费者问题
      5  * 分析:
      6  * 1、是否是多线程的问题:是多线程问题,至少要包含生产者线程和消费者线程
      7  * 2、是否有共享数据的问题?有共享数据:产品(这里只用了一个产品的个数进行表示)
      8  * 3、如何解决线程的安全问题:使用同步机制
      9  * 4、如何解决线程之间的通信问题?wait()和notify()/notifyAll()
     10  */
     11 //店员类
     12 class Clerk {
     13     private int productNumber = 0;
     14     //生产产品
     15     public synchronized void produceProductor() {
     16         if(productNumber<20){
     17             productNumber++;
     18             System.out.println(Thread.currentThread().getName()+":开始生产第"+productNumber+"个产品");
     19           //只要生产者生产出至少一个产品,就能唤醒消费者线程进行消费
     20             notify();
     21         }else{
     22             //当产品的个数大于20的时候,生产者线程就要进入阻塞状态,等待消费者线程消费产品之后在进行生产
     23             try {
     24                 wait();
     25             } catch (InterruptedException e) {
     26                 e.printStackTrace();
     27             }
     28         }
     29     }
     30     //消费产品
     31     public synchronized void consumerProduct() {
     32         if(productNumber>0){
     33             System.out.println(Thread.currentThread().getName()+":开始消费第"+productNumber+"个产品");
     34             productNumber--;
     35             //只要消费者线程进行了一次消费,就能唤醒生产者线程进行生产
     36             notify();
     37         }else{
     38             //当产品的个数小于等于0的时候,消费者线程就要进入阻塞状态,等待生产者生产出产品之后在进行消费
     39             try {
     40                 wait();
     41             } catch (InterruptedException e) {
     42                 e.printStackTrace();
     43             }
     44         }
     45     }
     46 }
     47 
     48 //生产者类
     49 class Productor extends Thread {
     50     private Clerk clerk;
     51 
     52     public Productor(Clerk clerk) {
     53         this.clerk = clerk;
     54     }
     55 
     56     @Override
     57     public void run() {
     58         System.out.println(Thread.currentThread().getName() + ":开始生产产品.....");
     59         while (true) {
     60             try {
     61                 Thread.sleep(100);
     62             } catch (InterruptedException e) {
     63                 e.printStackTrace();
     64             }
     65             clerk.produceProductor();
     66         }
     67     }
     68 }
     69 
     70 //消费者类
     71 class Consumer extends Thread {
     72     private Clerk clerk;
     73 
     74     public Consumer(Clerk clerk) {
     75         this.clerk = clerk;
     76     }
     77 
     78     @Override
     79     public void run() {
     80         System.out.println(Thread.currentThread().getName() + ":开始消费产品.....");
     81         while (true) {
     82             try {
     83                 Thread.sleep(100);
     84             } catch (InterruptedException e) {
     85                 e.printStackTrace();
     86             }
     87             clerk.consumerProduct();
     88         }
     89     }
     90 }
     91 //测试类,创建一个生产者生产商品,创建一个消费者消费产品
     92 public class ProductorTest {
     93     public static void main(String[] args) {
     94         Clerk clerk = new Clerk();
     95         Thread p1 = new Productor(clerk);
     96         p1.setName("生产者1");
     97         Thread c1 = new Consumer(clerk);
     98         c1.setName("消费者1");
     99         p1.start();
    100         c1.start();
    101     }
    102 }
  • 相关阅读:
    Message高级特性 & 内嵌Jetty实现文件服务器
    springboot中使用kindeditor富文本编辑器实现博客功能&vue-elementui使用vue-kindeditor
    Embarcadero RAD Studio XE5
    经典营销故事
    百度竞价教程 借助百度热力图让你的效果翻10倍
    无本借力:他是如何实现年收入70万?
    不用软件快速拥有几百个QQ群并都是管理员
    质保、保修、包修:含义不同
    域名反向解析在自建邮件群发服务器中的应用
    2014年1月1日,马年
  • 原文地址:https://www.cnblogs.com/BaoZiY/p/10727175.html
Copyright © 2011-2022 走看看