实践项目:生产者与消费者【经典多线程问题】

问题引出:

  生产者和消费者指的是两个不同的线程类对象,操作同一个空间资源的情况。

需求引出:

  —— 生产者负责生产数据,消费者负责取走数据

  —— 生产者生产完一组数据之后,消费者就要取走一组数据

设置三个类:数据类、生产类、消费类;生产和消费类是线程类,同时操作同一个数据类;生产类负责每次向数据类中写入一组数据;消费类负责每次从数据类中取出一组数据。

 package hello;

 class Info {  // 数据类
private String title ;
private String content;
public void setTitle(String title) {
this.title = title ;
}
public String getTitle() {
return title ;
}
public String getContent() {
return content ;
}
public void setContent(String content) {
this.content = content ;
} } class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ( x % 2 == 0 ) {
this.info.setTitle("张三");
this.info.setContent("男");
} else {
this.info.setTitle("王五");
this.info.setContent("男");
}
}
}
} class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.info.getTitle() + "——" + this.info.getContent());
}
}
} public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}

上例程序执行后,会发现“错位的现象”;出现类似数据为取走,就存入新的数据的错误。【不同步且异步现象导致】

 package hello;

 class Info {  // 数据类
private String title ;
private String content;
public synchronized void set(String title , String content) {
this.title = title ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} this.content = content ;
}
public synchronized void get() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + "——" + this.content);
} } class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
if ( x % 2 == 0 ) {
this.info.set("张三", "男");
} else {
this.info.set("李悦", "女");
}
}
}
} class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
this.info.get();
}
}
} public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}

通过“同步方法”,解决了数据不同步的问题,但是于此而来的问题就是:数据的重复操作。

针对上两例程序,我们通过Object类的支持,来解决数据重复操作的问题:
  如果像上例的设计,需要在程序中加入一个等待机制;当数据未取则等待数据取出后在存入,当数据未存等待数据存入后取出。而Object类中提供有专门的“等待”。

等待:    public final void wait() throws InterruptedException
唤醒第一个等待线程:    public final void notify() ;
唤醒全部的等待进入:    public final void notifyAll();  //优先级高越有可能先唤醒

通过Object的线程等待和唤醒功能完善程序:

 package hello;

 class Info {  // 数据类
private String title ;
private String content;
private boolean flag = true ;
// true:表示可以生产,不可以取走
// false:表示不可以生产,可以取走
public synchronized void set(String title , String content) {
if (this.flag == false) { // 发现不可以生产,则等待线程
try {
super.wait(); // 通过super调用自己的超类(父类)Object类中的wait()方法等待线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content ;
this.flag = false ;// 修改标记
super.notify(); //唤醒其他等待线程
}
public synchronized void get() {
if (this.flag == true) {
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + "——" + this.content);
this.flag = true ; //修改标记
super.notify(); // 唤醒其他线程
} } class Producer implements Runnable { // 生成者类(线程)
private Info info ;
public Producer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++ ) {
if ( x % 2 == 0 ) {
this.info.set("张三", "男");
} else {
this.info.set("李悦", "女");
}
}
}
} class Consumer implements Runnable {
private Info info ;
public Consumer(Info info) {
this.info = info ;
}
@Override
public void run() {
for (int x = 0 ; x < 100 ; x ++) {
this.info.get();
}
}
} public class TestDemo {
public static void main(String[] args) throws Exception {
Info info = new Info() ;
new Thread(new Producer(info)).start();
new Thread(new Consumer(info)).start();
}
}

我们依靠Object类中的等待唤醒机制完成了代码的要求。

------------------------

Java 实践:生产者与消费者的更多相关文章

  1. Windows下RabbitMQ 的下载、配置、Java实现生产者和消费者例子

    RabbitMQ是一个轻量级的消息代理中间件,支持多种消息通信协议,支持分布式部署,支持运行于多个操作系统,具有灵活.高可用等特性.RabbitMQ支持多种协议,其中最为重要的是高级消息队列协议(AM ...

  2. java实现生产者和消费者问题

    Java实现生产者和消费者问题 欢迎访问我的个人博客,获取更多有用的东西 链接一 链接二 也可以关注我的微信订阅号:CN丶Moti

  3. Java实现生产者和消费者

    生产者和消费者问题是操作系统的经典问题,在实际工作中也常会用到,主要的难点在于协调生产者和消费者,因为生产者的个数和消费者的个数不确定,而生产者的生成速度与消费者的消费速度也不一样,同时还要实现生产者 ...

  4. java之生产者与消费者

    package com.produce; import java.util.LinkedList; import java.util.Queue; /*@author shijin * 生产者与消费者 ...

  5. java线 生产者和消费者

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  6. Java实现生产者与消费者模式

    生产者不断向队列中添加数据,消费者不断从队列中获取数据.如果队列满了,则生产者不能添加数据:如果队列为空,则消费者不能获取数据.借助实现了BlockingQueue接口的LinkedBlockingQ ...

  7. Java中生产者与消费者模式

    生产者消费者模式 首先来了解什么是生产者消费者模式.该模式也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线 ...

  8. java之生产者和消费者问题

    package testThread; public class Test3 { public static void main(String[] args) { Clerk c = new Cler ...

  9. 菜鸡的Java笔记 生产者与消费者

    生产者与消费者        代码要求知道做什么用即可        线程间的通讯问题以及 Object 类的支持            基础模型        现在希望实现一种数据的生产和取出的操作 ...

  10. Java 多线程-生产者、消费者

    一.整体代码 ThreadDemo.java public class ThreadDemo { public static void main(String[] args) { Godown god ...

随机推荐

  1. Android6.0 源码修改之Setting列表配置项动态添加和静态添加

    写在前面 最近客户有个需求,要求增加操作Setting列表配置项的功能,是不是一脸懵,没关系,一图胜千言,接下来就上图.诺,就是这么个意思.   原来的列表配置项     增加了单个配置项     增 ...

  2. CKEditor5 使用第二天 获取回传数据,图片上传

    1.当系统中存在编辑功能时,需要将数据库中数据回显到页面,因此采用了最一般的方法,通过隐藏的input标签存贮,在通过CkEditor5中的setData方法将数据赋值到富文本框中 <texta ...

  3. Spring Boot 2 读取配置文件

    开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目. 一.默认配置文件 Spring Boot会读取名称a ...

  4. pip 查看软件包 可用版本并安装; pip 查看 numpy 可用版本并安装

    最近需要安装 numpy 的旧版本,发现不知道如何查看可以安装旧版本,解决方法在此进行记录: 然后找到你对应的版本进行安装就可以了: 保持更新,更多精彩内容,请关注 cnblogs.com/xuyao ...

  5. s3c2440裸机-UART编程(二、UART编程实现)

    UART编程 1.初始化 我们的2440支持3个UART串口,以uart0为例讲解. 那么我们需要实现以下这几个函数完成串口的最基本功能: (1)uart0_init()用于初始化串口 (2)putc ...

  6. idea延长使用期

    0. 如果你的idea(版本2019.02)是已过期状态则先上网找个激活码激活再进行下面步骤延长使用期至2089年 1. 附件下载地址: 链接:https://pan.baidu.com/s/1L5O ...

  7. JSON格式日期的转换

    扒来的链接: https://blog.csdn.net/zhang33565417/article/details/99676975 感谢这位哥们儿的分享!

  8. vscode 问题。。。。

    "program": "${workspaceFolder}/a.out", "preLaunchTask": "build&qu ...

  9. 2个ajax的相互调用解决异步问题

  10. python-12-字典的嵌套与int快速排序

    前言 字典的增删改查我们都有一定的认识与了解啦,但是字典也可以嵌套列表.字典.元组等数据结构. 一.字典的嵌套 1.修改.添加 dic = { "name": ["lin ...