一、解决方法: synchronized,wait,notify

1、使用wait方法和notify方法实现“生产者和消费者模式”

2、什么是“生产者和消费者模式”?
    生产线程负责生产,消费线程负责消费。
    生产线程和消费线程要达到均衡

3、wait和notify方法不是线程对象的方法,是普通java对象都有的方法。

4、wait方法和notify方法建立在线程同步(synchronized 两个线程进行抢一把锁 排队)的基础之上。
   因为多线程要同时操作一个仓库。有线程安全问题。

5、wait方法作用:o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉t线程之前占有的o对象的锁。
[如:两个线程共享一个仓库对象o 一个线程o.wait() 那么这个线程将会释放掉o对象的锁 供另外一个线程使用]

6、notify方法作用:o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放o对象上之前占有的锁。

要求:

模拟这样一个需求:
    仓库我们采用List集合。
    List集合中假设只能存储1个元素。
    1个元素就表示仓库满了。
    如果List集合中元素个数是0,就表示仓库空了。
    保证List集合中永远都是最多存储1个元素。
    必须做到这种效果:生产1个消费1个。

代码演示: (注释详细)
package com.bipowernode.javase.thread.shengcanzhe; import java.util.ArrayList;
public class ThreadTest01 { public static void main(String[] args) { //
创建一个仓库对象 共享的 (一个对象一把锁) ArrayList<Bread> arrayList =new ArrayList<>(); //
只能存储Bread对象的List集合对象 // 创建两个线程 Thread t1 =new Thread(new Producer(arrayList));
Thread t2 =new Thread(new Consumer(arrayList)); // 设置name t1.setName("生产者线程");
t2.setName("消费者线程"); // 开启线程 t1.start(); t2.start(); // 因为两个线程共享一个仓库对象,
有synchronized关键字修饰,那么t1、t2线程就需要进行抢锁,先抢到了先执行, //
假设t1先抢到对象锁,那么t1线程run先跑程序,此时t2等着对象锁,等t1把对象锁释放后t2拿到锁开始执行 } } // 生产线程 class
Producer implements Runnable{ // 拿到仓库对象 ArrayList<Bread> list; // 通过构造方法拿到仓库对象
public Producer(ArrayList<Bread> list){ this.list =list; } @Override public
void run() { // 一直生产(死循环) while (true){ // synchronized :
因为两个线程共享该仓库对象,让两个线程抢锁的目的是保证线程安全 synchronized (list){ // 当前对象锁:当前对象是list仓库对象 if
(list.size() >0){ // 大于0,说明仓库中已经有一个元素了 仓库已经满了等着消费进程进行消费 try { list.wait(); //
仓库满了 让当前线程进入等待状态,并且释放掉list集合对象的锁, 因为一个对象就一把锁 } catch (InterruptedException e) {
// 假设生产线程synchronized已经抢到了这把锁, 这里要把锁释放掉 消费线程才能拿到锁跑程序 e.printStackTrace(); } }
// 程序能执行到这里 说明仓库为空 // 向仓库中添加元素 Bread bread =new Bread("面包~"); list.add(bread);
System.out.println(Thread.currentThread().getName() +"生产了:" +bread.getName());
// 生产完毕后 唤醒消费者进行消费 list.notify(); // 代码全部执行完毕后,此生产者会释放掉对象锁 然后重新开始抢对象锁,
有可能释放后对象锁被消费线程抢到了 // 也有可能释放掉后生产者又抢到了对象锁, 但即使生产者又抢到了对象锁 仓库已经满了 生产者还是只能释放对象锁 //
进入等待状态 (执行效率低) } } } } // 消费线程 class Consumer implements Runnable{ // 拿到仓库对象
ArrayList<Bread> list; // 通过构造方法拿到仓库对象 public Consumer(ArrayList<Bread> list){
this.list =list; } @Override public void run() { // 一直消费 while (true){
synchronized (list){ if (list.size() ==0){ // 仓库集合等于0 说明仓库为空
进入等待状态,同生产线程一样把对象锁释放掉,让生产者生产 try { list.wait(); // 进入等待状态,释放掉对象锁 } catch
(InterruptedException e) { e.printStackTrace(); } } // 代码执行到这里 说明仓库满了 需要进行消费
Bread bread =list.remove(0);
System.out.println(Thread.currentThread().getName() +"消费了:" +bread.getName());
// 同理 消费后 唤醒生产线程 开始生产面包 list.notify(); } } } }
面包类:
package com.bipowernode.javase.thread.shengcanzhe; public class Bread {
private String name; public Bread(String name) { this.name = name; } public
String getName() { return name; } public void setName(String name) { this.name
= name; } // 重写toString方法 @Override public String toString() { return name; } }
输出结果:

 

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信