生产者消费者模型

生产者消费者模型是什么

生产者和消费者彼此之间不直接通讯,而是通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取。阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三者是工厂类,模板模式的第三者是模板类。生产者消费者模型属于架构设计,类似于我们所说的设计模式,用于解决生产者和消费者速率不匹配的问题这一类问题,架构设计上使得消费者生产者解耦。

wait()方法

① 使当前线程进行等待,将当前线程置于“预执行队列”中,要想继续执行,除非被 notify() 或被中断

② 要在同步代码块或同步方法中使用,否则会报错!!!

③ wait() 执行完成后,当前线程释放锁,进行下一轮竞争

package com.xxx;

public class TestWait {

    public static void main(String[] args) {

        Object object = new Object();
        synchronized (object) {

            System.out.println("开始执行");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束执行");
        }
    }
}

从上述代码我们发现执行object.wait()之后程序就在一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个唤醒线程的方法notify()

notify()方法

① 通知那些可能等待该对象的对象锁的线程,对其发出通知 notify,使它们重新获得该对象的对象锁

② 如果有多个线程在等待,则由线程规划器随机挑选一个呈 wait 状态的线程,该方法会造成阻塞

③ 要在同步代码块或同步方法中使用,否则会报错!!!

④ notify() 方法不会马上释放对象锁,要等 notify() 方法的线程将程序执行完,即退出同步代码块之后才会释放对象锁

package com.xxx;

public class TestNotify {

    public static void main(String[] args) {

        final Object monitor = new Object();

        Thread threadWait = new MyWaitThread(monitor);
        threadWait.setName("Thread-wait");

        Thread threadNotify = new MyNotifyThread(monitor);
        threadNotify.setName("Thread-notify");

        threadWait.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadNotify.start();
    }
}

class MyWaitThread extends Thread {

    private final Object monitor;

    public MyWaitThread(Object monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {

        synchronized (this.monitor) {
            System.out.println(Thread.currentThread().getName() + "开始执行");

            try {
                this.monitor.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "结束执行");
        }
    }
}

class MyNotifyThread extends Thread {

    private final Object monitor;

    public MyNotifyThread(Object monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        synchronized (this.monitor) {
            System.out.println(Thread.currentThread().getName() + "开始执行");

            //通知一个线程
            this.monitor.notify();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "结束执行");
        }
    }
}

在这里插入图片描述
第一个线程里面有个死循环并且使用了 wait 方法进入等待状态,如果这个线程不被唤醒的话将会一直等待下去,这个时候第二个线程执行的是 notify 方法,将线程一唤醒继续执行。

notifyAll()方法

以上所说的 notify 方法只是唤醒某一个等待线程,那么如果有多个线程都在等待中怎么办呢,这个时候就可以使用 notifyAll 方法可以一次唤醒所有的等待线程。

package com.xxx;

public class TestNotify {

    public static void main(String[] args) {

        final Object monitor = new Object();

        Thread threadWait = new MyWaitThread(monitor);
        threadWait.setName("Thread-wait");

        Thread threadWait2 = new MyWaitThread(monitor);
        threadWait2.setName("Thread-wait2");

        Thread threadNotify = new MyNotifyThread(monitor);
        threadNotify.setName("Thread-notify");

        threadWait.start();
        threadWait2.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadNotify.start();
    }
}

class MyWaitThread extends Thread {

    private final Object monitor;

    public MyWaitThread(Object monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {

        synchronized (this.monitor) {
            System.out.println(Thread.currentThread().getName() + "开始执行");

            try {
                this.monitor.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "结束执行");
        }
    }
}

class MyNotifyThread extends Thread {

    private final Object monitor;

    public MyNotifyThread(Object monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        synchronized (this.monitor) {
            System.out.println(Thread.currentThread().getName() + "开始执行");

            //通知多个线程
            this.monitor.notifyAll();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + "结束执行");
        }
    }
}

在这里插入图片描述
注意:不能过早地唤醒线程。如果在还没有线程在等待时,过早的唤醒线程,这个时候就会出现先唤醒再等待的效果了。这样就没有必要在去执行 wait 方法了。

生产者消费者模型

生产者与消费者开头已经介绍过了,生产者与消费者一般需要第三者来解耦的,所以现在就模拟一个简单的生产者与消费者,由生产者线程生产出一个商品之后将由消费者线程开始消费!

商品类

package com.xxx;

/**
 * Goods:生产者生产的产品类
 */
public class Goods {

    private final String id;
    private final String name;

    public Goods(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

生产者

package com.xxx;

/**
 * 生产者:
 * 1.生产商品
 * 2.将生产好的商品添加到容器中
 * 3.若容器已满,等待消费者消费
 */
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;

public class Producer implements Runnable {

    private final Queue<Goods> queue;

    private final Integer maxCapacity = 10;

    //原子变量
    private final AtomicInteger id = new AtomicInteger(0);

    public Producer(Queue<Goods> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {

        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (this.queue) {
                if(queue.size() == maxCapacity) {
                    System.out.println(Thread.currentThread().getName() + "容器满了,等待消费");

                    try {
                        this.queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {

                    //获取id:
                    //UUID.randomUUID().toString()/AtomicInteger
                    //getAndIncrement():获取之后再增加
                    Goods good = new Goods(String.valueOf(id.getAndIncrement()), "A商品");
                    System.out.println(Thread.currentThread().getName() + "生产商品" + good);
                    this.queue.add(good);

                }
            }
        }
    }
}

消费者

package com.xxx;

/**
 * 消费者:
 * 1.消费商品
 * 2.从容器中取出商品
 * 3.若容器为空,通知生产者生产
 */
import java.util.Queue;

public class Customer implements Runnable {

    private final Queue<Goods> queue;

    public Customer(Queue<Goods> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {

        while(true) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (this.queue) {
                if(this.queue.isEmpty()) {
                    System.out.println(Thread.currentThread().getName() + "容器已空,通知生产");

                    this.queue.notifyAll();
                } else {
                    Goods good = this.queue.poll();
                    if(good != null) {
                        System.out.println(Thread.currentThread().getName() + "消费商品" + good);
                    }
                }
            }
        }
    }
}

测试类

package com.xxx;

import java.util.LinkedList;
import java.util.Queue;

public class TestProducerCustomer {

    public static void main(String[] args) {

        final Queue<Goods> queue = new LinkedList<>();
        final Runnable producer = new Producer(queue);
        final Runnable customer = new Customer(queue);

        //生产者线程
        for(int i = 0; i < 5; i++) {
            new Thread(producer, "Thread-producer-" + i).start();
        }

        //消费者线程
        for(int i = 0; i < 8; i++) {
            new Thread(customer, "Thread-customer-" + i).start();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值