Java 多线程 —— 生产者消费者问题

  1. 线程抢到了CPU后,可以在很短的时间内运转多次。

这样可能出现只有一个货架,生产者生产完商品后,还没有等消费者来取,就不断的生产新的商品来替代货架上的旧商品的情况。或者消费者已经将商品取走,还在对着空的货架不断取商品的情况。

解决办法:加入等待唤醒机制

等待唤醒机制通过Object类中的三个方法来实现(注意是Object,不是Thread):

void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。

void notify() 唤醒正在等待对象监视器的单个线程。

void notifyAll() 唤醒正在等待对象监视器的所有线程。

这三个方法的具体使用是:

  1. wait()

在调用 wait()之前,线程必须要获得相应对象的对象监视器锁(这里是Student对象),所以只能在同步方法或同步块中调用 wait()方法。对象调用wait()方法后,当前线程会立即释放锁,然后进入休眠状态,直到被notify()唤醒或者被中断。同时线程的执行会在wait()语句处停止,直到再次获得锁,当前线程才能从wait()方法处成功返回,然后继续执行下面的代码。另外,被释放的锁会立刻被其他等待锁的线程抢夺,抢到锁的线程开始执行同步代码块。

  1. notify()

notify()同样需要获得锁,并且只能在同步方法或同步代码块中调用。当前线程调用notify()后,会唤醒之前wait()后陷入休眠的线程,使其从等待队列进入同步队列,获取当前线程的锁,并且从之前wait()语句处继续执行(这里要求对象锁的对象要一致,才会去唤醒)。当等待唤醒的线程较多时,会根据机制随机挑选一个线程唤醒。当前线程调用notify()方法后不会立刻释放锁,而是继续执行,直到执行结束退出同步方法或同步代码块时,才会释放锁。

  1. notifyAll()

notifyAll()与notify()的工作方式大致相同,不同的是等待线程较多时,notify()会随机挑选一个线程通知,而notifyAll()会将所有具有相同对象锁的线程全部唤醒,让这些线程争抢锁。

这里注意wait()与notify(),notifyAll()联系的桥梁是相同的对象,即synchronized(对象){ },不同的线程之间,括号里面的对象相同

生产者线程

package test.MyThread.ProductDemo;

public class SetThread implements Runnable{

Student s ;

int x = 0;

public SetThread(Student s){

this.s = s;

}

@Override

public void run() {

while(true){

synchronized(s){

if(s.flag){

//说明已经给学生对象赋值,应该等待消费者来获取

try {

s.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}else{

//这里是两类商品,当x%2==0的时候上架商品水果,否则上架商品面包

//这里放在学生类里面想当于一个叫水果的学生,一个叫面包的学生

if(x%2==0){

s.setName(“水果”);

s.setAge(18);

}else{

s.setName(“面包”);

s.setAge(15);

}

x++;

//赋值完毕,将状态转为true,并通知消费者来取值

s.flag = true;

s.notify();

}

}

}

}

}

消费者线程

package test.MyThread.ProductDemo;

public class GetThread implements Runnable{

Student s ;

public GetThread(Student s){

this.s = s;

}

@Override

public void run() {

while(true){

synchronized(s){

//s.flag为false时,!s,flag为true,运行if语句

if(!s.flag){

try {

s.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(s.name + “—” + s.age);

s.notify();

s.flag = false;

}

}

}

}

s.flag=true说明有商品,s.flag=false说明没有商品

这里没有商品的时候应该用锁对象调用wait()方法,线程释放锁对象,并且代码的执行停留在这一步

锁对象被释放后,会被生产者抢夺,而消费者不会再抢夺锁对象

然后生产者生产商品完毕后,用notify()方法唤醒消费者,并且将锁对象给消费者

调用notify()方法后不会立刻释放锁对象,而是等生产者将同步代码块全部运行完之后才会释放给消费者

这样生产者会继续从头运行,检测是否有商品,如果商品还没有被消费者消费,那么就进入等待状态

最后消费者接着执行代码,消费商品,消费完毕后用notify()方法唤醒生产者生产商品

package test.MyThread.ProductDemo;

public class StudentDemo {

public static void main(String[] args) {

Student s = new Student();

SetThread s1 = new SetThread(s);

GetThread g1 = new GetThread(s);

Thread t1 = new Thread(s1);

Thread t2 = new Thread(g1);

t1.start();

t2.start();

}

}

运行一下,结果为

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值