Java 多线程 —— 生产者消费者问题,从基础到深入案例

HarmonyOS学习 2021-11-25 18:56:29
java 面试 编程语言 后端开发

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

假设这个Student学生类是货架,name姓名和age年龄是货架上面的商品。而flag标志则用来说明货架是否为空。

消费者线程获取学生的姓名和年龄等同于消费者获取商品。生产者给学生对象赋新的姓名和年龄的值,等同于生产者生产商品

这里将消费者获取了name和age就将flag设置为false,即货架为空。而生产者给name和age设置新的值,就将flag设置为true,即货架已满

在编写生产者和消费者的线程的代码前,首先有几个问题要来解决:

  1. 我们要确保生产者和消费者,是针对同一个学生对象操作的。

因为消费者消费的商品一定是生产者生产的,如果操作的对象不一样,那么消费者永远取不到商品。

解决办法是:在主方法的外面构造学生对象,然后给生产者和消费者都加上一个有参构造方法,将学生对象作为参数传入生产者和消费者之中。而不是在线程内部新建一个学生对象

  1. 这是否涉及到线程安全问题,来看看线程安全问题的三个条件

(1)是否存在多线程环境 (存在,生产者和消费者线程)

(2)是否存在共享数据 (存在,Student对象)

(3)是否有多条语句操作着共享数据 (是)

解决方法:synchronized,同步代码块

当生产者给对象赋值的时候,消费者无法操作对象取值,避免了生产者只给对象的name赋值,而消费者已经把name和age的值都取走的情况

  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(1

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

8);

}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;

最后的内容

在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)

如何准备面试?

1、前期铺垫(技术沉积)

程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。

下面是我会看的一些资料笔记,希望能帮助大家由浅入深,由点到面的学习Java,应对大厂面试官的灵魂追问

这部分内容过多,小编只贴出部分内容展示给大家了,见谅见谅!

  • Java程序员必看《Java开发核心笔记(华山版)》

Java 多线程 —— 生产者消费者问题,从基础到深入案例_面试

  • Redis学习笔记

Java 多线程 —— 生产者消费者问题,从基础到深入案例_后端开发_02

  • Java并发编程学习笔记

四部分,详细拆分并发编程——并发编程+模式篇+应用篇+原理篇

Java 多线程 —— 生产者消费者问题,从基础到深入案例_面试_03

  • Java程序员必看书籍《深入理解 ava虚拟机第3版》(pdf版)

Java 多线程 —— 生产者消费者问题,从基础到深入案例_Java_04

  • 大厂面试必问——数据结构与算法汇集笔记

Java 多线程 —— 生产者消费者问题,从基础到深入案例_面试_05

其他像Spring,SpringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。

Java 多线程 —— 生产者消费者问题,从基础到深入案例_Java_06

2、狂刷面试题

技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。

①大厂高频45道笔试题(智商题)

Java 多线程 —— 生产者消费者问题,从基础到深入案例_Java_07

②BAT大厂面试总结(部分内容截图)

Java 多线程 —— 生产者消费者问题,从基础到深入案例_后端开发_08

Java 多线程 —— 生产者消费者问题,从基础到深入案例_后端开发_09

③面试总结

Java 多线程 —— 生产者消费者问题,从基础到深入案例_面试_10

Java 多线程 —— 生产者消费者问题,从基础到深入案例_后端开发_11

3、结合实际,修改简历

程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:

Java 多线程 —— 生产者消费者问题,从基础到深入案例_Java_12

以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

本文已被 CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

版权声明
本文为[HarmonyOS学习]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15438507/4690495

  1. 图解 Kafka 线程模型及其设计缺陷
  2. Add data files for Oracle tablespaces or temporary tablespaces
  3. Intellij IDEA神器居然还有这些小技巧,mysql集群搭建视频
  4. IntelliJ IDEA(2019)之Web项目创建,掌门一对一java面试题
  5. InnoDB(2,如何访问Redis中的海量数据
  6. InheritableThreadLocal使用详解,java多线程面试题及答案整理
  7. How does Oracle modify the data type of a column
  8. Oracle 12C 12.1.0.1.0 management control file official document translation instructions
  9. Oracle 10g 10.2.0.1 in Oracle Linux 5.4 32bit RAC installation manual (Yimo Xiyang)
  10. Oracle 12C in Oracle Linux 6.5 64bit installation manual
  11. 一天十道Java面试题----第一天(面向对象-------》ArrayList和LinkedList)
  12. Schéma du modèle de fil Kafka et de ses défauts de conception
  13. Starting and shutting down Oracle RAC database cluster
  14. CRS_ Oracle CRS stack is already configured and will be running under init(1M)
  15. Common skills of Oracle stored procedure
  16. Check the number of CPUs, core books and threads of the Linux system
  17. jQuery-实例方法
  18. Oracle de duplicated data
  19. jQuery-dom和jQuery,入口函数(基本知识)
  20. Oracle creates unique constraints on columns that already have duplicate data
  21. JavaScript-拷贝
  22. JavaScript-this指向问题
  23.  There is ^ [[a garbled code problem in the up and down keys in Oracle sqlplus
  24. JavaScript-封装与继承(两种)
  25. JavaScript-包装类型
  26. JavaScript-传值(引用类型,基本类型)
  27. JavaScript-面向对象(构造函数,实例成员,静态成员)
  28. JavaScript-解构赋值
  29. JavaScript-箭头函数
  30. JavaScript-参数
  31. JavaScript-预解析(变量提升)
  32. JavaScript-闭包closure
  33. JavaScript-声明变量的关键字
  34. JavaScript - mot - clé pour déclarer une variable
  35. Fermeture de fermeture JavaScript
  36. JavaScript Pre - parse (promotion des variables)
  37. Paramètres JavaScript
  38. Fonction de flèche JavaScript
  39. JavaScript - déconstruction assignations
  40. Common annotations in springboot
  41. Building CentOS 7.6 with Linux
  42. JavaScript - orienté objet (constructeur, membre d'instance, membre statique)
  43. JavaScript value Transfer (reference type, Basic type)
  44. JavaScript - type d'emballage
  45. linux deepin/ubuntu安装flameshot火焰截图
  46. JavaScript - encapsulation et héritage (deux)
  47. JavaScript JS method for writing 99 multiplication table
  48. 從零開始學java - 第二十五天
  49. Apprendre Java à partir de zéro - jour 25
  50. Les voitures d'hiver, les voitures électriques et les voitures à essence ne sont pas les mêmes?
  51. JavaScript - ceci pointe vers le problème
  52. Copie JavaScript
  53. Spring boot quickly integrates swagger
  54. linux deepin/ubuntu安裝flameshot火焰截圖
  55. Capture d'écran de flamme de l'installateur de flamme Linux deepin / Ubuntu
  56. Jquery DOM et jquery, fonctions d'entrée (bases)
  57. Méthode d'instance jquery
  58. Méthode et démonstration de code dans l'interface de liste en Java
  59. Démarrage du Zookeeper
  60. Java oom Cognition