• Java线程通信-生产者消费者问题


    线程通信示例——生产者消费者问题

    这类问题描述了一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费.假设仓库中没有产品,则生产者可以将 产品放入仓库,有产品,则停止生产并等待,直到仓库中的产品被消费这取走为止. 如果仓库中放油产品,则消费者可以将产品取走消费,否则停止消费并等待,直到 仓库中再次放入产品为止. 显然,这是一个同步问题,生产者和消费这共享同一资源, 并且生产者和消费这之间彼此依赖,互为条件向前推进.Java提供了3个方法解决了线程间的通信问题,分别是wait() notify() 和 notifyAll()
    * (1)调用wait()方法: 使调用该方法的线程释放共享资源的锁,然后从运行状态退出, 进入等待队列,直到被再次唤醒
    * (2)调用notify()方法: 唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待,进入就绪状态
    * (3)调用notifyAll()方法: 使所有正在等待队列中同一共享资源的线程从等待状态退出,此时优先级最高的那个线程最先执行

    /* wait()方法使调用该方法的线程释放共享资源的锁,然后从运行状态退出, 进入等待队列,直到被再次唤醒 */ 

      1 package com.iotek.productconsumerdemo;
      2 
      3 import java.util.LinkedList;
      4 
      5 public class ProductorConsumerDemo {
      6 
      7     /**
      8      * 线程通信-wait() notify() notifyAll() 
      9      * 在现实应用中,很多时候需要让那个多个线程按照i定的次序来访问共享资源,例如经典的生产者消费者问题:
     10      * 这类问题描述了这样一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者
     11      * 将仓库中的产品取走消费,如果仓库中没有产品,在生产者可以将产品放入仓库,否则停止生产并等待,直到
     12      * 仓库中的产品被消费这取完为止,如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,
     13      * 直到仓库中再次放入产品为止
     14      * @param args
     15      * 
     16      */
     17     public static void main(String[] args) {
     18         Basket basket = new Basket();
     19         Productor productor = new Productor(basket);//创建生产者对象
     20         Consumer consumer = new Consumer(basket);//创建消费者对象
     21         productor.start();  //生产者启动生产
     22         consumer.start();   //消费者开始消费
     23     }
     24 
     25 }
     26 
     27 class Consumer extends Thread {
     28     private Basket basket = null;
     29 
     30     public Consumer(Basket basket) {
     31         this.basket = basket;
     32     }
     33     @Override
     34     public void run() {
     35         basket.popApple();  //消费者从篮子里取苹果
     36     }
     37 }
     38 
     39 class Productor extends Thread {
     40     private Basket basket = null;
     41 
     42     public Productor(Basket basket) {
     43         this.basket = basket;
     44     }
     45 
     46     @Override
     47     public void run() {
     48         basket.pushApple(); // 生产者向篮子里放苹果
     49     }
     50 }
     51 
     52 // 篮子类,用来存放苹果(需要一个容器来存放,频繁存取,用LinkedList),或者取苹果
     53 class Basket {
     54     private LinkedList<Apple> basket = new LinkedList<Apple>();
     55 
     56     // 放四轮苹果
     57     public synchronized void pushApple() {
     58         // synchronized 加锁,放苹果的时候不能取苹果
     59         for (int i = 0; i < 20; i++) {
     60             Apple apple = new Apple(i);
     61             push(apple);
     62         }
     63     }
     64 
     65     // 取4轮苹果
     66     public synchronized void popApple() {
     67         for (int i = 0; i < 20; i++) {
     68             pop();
     69         }
     70     }
     71 
     72     // 向篮子里面放苹果 这个方法不对外使用,因此设置为private私有的
     73     /* public */private void push(Apple apple) {
     74         // 如果篮子里已经有5个苹果了,就等待并通知消费者来消费
     75         if (basket.size() == 5) {
     76             try {
     77                 wait();// 等待,并释放当前对象的锁
     78                 /* 注意!!!调用wait()方法进入等待的线程,必须要通过其他线程调用notify()或notifyAll()方法来唤醒 */
     79             } catch (InterruptedException e) {
     80                 e.printStackTrace();
     81             }
     82         }
     83         // 如果没满5个苹果,那么就继续放苹果
     84         try {
     85             Thread.sleep(500);// 每隔500ms放一个苹果
     86             // sleep()使当前线程每隔设定的休眠时间后,就自动启动线程
     87         } catch (InterruptedException e) {
     88             e.printStackTrace();
     89         }
     90         basket.addFirst(apple);// 存放苹果
     91         System.out.println("存放:" + apple.toString());
     92         notify();// 通知消费者来消费
     93     }
     94 
     95     // 从篮子中取苹果
     96     /* public */private void pop() {
     97         // 当篮子中苹果数为0 的时候就等待并通知生产者来生产
     98         if (basket.size() == 0) {
     99             try {
    100                 wait();
    101             } catch (InterruptedException e) {
    102                 e.printStackTrace();
    103             }
    104         }
    105         // 如果篮子中苹果不为0,那么就消费,每隔一定间隔,消费一个苹果
    106         try {
    107             Thread.sleep(500);
    108         } catch (InterruptedException e) {
    109             e.printStackTrace();
    110         }
    111         Apple apple = basket.removeFirst();// 取出一个苹果
    112         System.out.println("吃掉:" + apple.toString());
    113         notify(); // 通知生产者来生产:notify()方法唤醒等待队列中第一个等待同一共享资源的线程,并使该线程进入就绪状态
    114 
    115     }
    116 }
    117 
    118 // 苹果类
    119 class Apple {
    120     private int id;
    121 
    122     public Apple(int id) {
    123         this.id = id;
    124     }
    125 
    126     @Override
    127     public String toString() {
    128         return "苹果:" + (id + 1);
    129     }
    130 }
  • 相关阅读:
    java 变量常量作用域
    简述Integer
    简述(非)静态代码块和构造方法的执行顺序
    父类子类在有(无)参构造方法继承的一些规则
    equals和==的区别
    创建和调用自定义类的方法简述
    int变量与double变量混合运算时的常见问题及方法
    int变量运算过程中的常见问题及方法
    初始Java
    Eclipse常用快捷键
  • 原文地址:https://www.cnblogs.com/enjoyjava/p/8192461.html
Copyright © 2020-2023  润新知