zoukankan      html  css  js  c++  java
  • 多线程之生产者消费者同步

    今天复习了一下多线程的知识,突然看到了马老师讲的多线程的例子,“吃馒头”

    有多个做馒头的师傅——生产者,同时又有多个拿馒头的人——消费者,

    师傅们做好馒头之后往桶里面(栈)丢馒头,顺序当然是按照FILO(先进后出),

    下来开始模拟生产者线程做馒头 然后消费者线程拿馒头

    根据面向对象的思想,一切东西皆对象,所以,先创建一个“桶”对象,一个馒头对象,一个生产者/消费者对象,

    下一步,为了记录馒头的位置,给馒头加入了id属性,生产者每次往馒头里面丢馒头的时候都会根据这个索引顺序进行添加,同时消费者也会遵循这个顺序的倒序进行消费(堆栈的先进后出),然后给桶加入构造方法,ps:给桶里装如馒头。

    重点:因为生产消费都在一个桶里面操作,为了防止同一时刻消费者消费/生产者生产的馒头“消失”(高并发),所以需要加入synchronized的关键字,当消费者发现桶里的馒头为空时,通知生产者去生产(这个时候消费者要调用Object类的wait()方法释放当前线程的锁,让生产者进行加锁并且生产馒头)

    生产者生产的馒头不为0时,同时调用notify()通知 消费者去消费,为了让例子结果更加明显,Thread.sleep()设置的时间在2秒左右

    在生产者/消费者线程实现runnable接口以标记为线程类,并调用其start()方法,

    import java.util.LinkedList;
    import java.util.List;
    
    public class ProducerConsumerTest{
    
        public static void main(String[] args) {
            Stack stack = new Stack();
            Producer producer = new Producer(stack);
            Consumer consumer = new Consumer(stack);
            new Thread(producer).start();
            new Thread(consumer).start();
        }
    
    }
    
    /**
     * 装馒头的桶
     */
    class Stack{
    
        private List<Mantou> mantous = null;
        private Integer index = 0;//放馒头的顺序
        public Stack(){
            if(mantous==null){
                mantous = new LinkedList<>();
            }
        }
        //装馒头
        public synchronized void push(Mantou mantou){
    
            mantous.add(mantou);
            index++;
            this.notify();
        }
        //拿馒头
        public synchronized  Mantou pull(){
            while (index==0){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.notify();
            index--;
            return mantous.get(index);
        }
    }
    class Mantou{
    
        private Integer id ;
    
        public Mantou(Integer id){
            this.id = id;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    }
    
    class Producer implements Runnable{
    
        private Stack stack;
    
        Producer(Stack stack){
            this.stack = stack;
        }
        @Override
        public void run() {
            for (int i = 0;i<20;i++){
                Mantou mantou = new Mantou(i);
                //丢馒头
                stack.push(mantou);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("  生产了 "+mantou.getId() + "个馒头");
            }
        }
    }
    class Consumer implements Runnable{
    
        private Stack stack;
    
        Consumer(Stack stack){
            this.stack = stack;
        }
        @Override
        public void run() {
            for (int i = 0;i<20;i++){
                //消费馒头
                Mantou mantou = stack.pull();
                System.out.println("  消费了 "+mantou.getId() + "个馒头");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    

      

    至此,本例子已模拟完!本例子记录我复习多线程的知识的感想。如有错误,请提出评论区,谢谢!

    ,一个馒头对象

  • 相关阅读:
    Docker安装
    MVC-HtmlHelper简单总结
    D3.js
    分布式事务seata
    彻底搞懂JAVA路径问题
    idea 代码生成
    自动生成 serialVersionUID 的设置
    狂神说SSM框架系列连载
    缓存穿透、缓存击穿、缓存雪崩区别和解决方案
    多线程
  • 原文地址:https://www.cnblogs.com/ChoviWu/p/8666937.html
Copyright © 2011-2022 走看看