Java基础教程:多线程基础(3)——阻塞队列

Java基础教程:多线程基础(3)——阻塞队列

快速开始

引入问题

  生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据

模拟情景

  这里我们实现如下的情况的生产-消费模型:

生产者不断交替地生产两组数据“姓名--1-->内容--1”,“姓名--2-->内容--2”,这里的“姓名--1”和“姓名--2”模拟为数据的名称,“内容--1 ”和“内容--2 ”模拟为数据的内容

由于本程序中牵扯到线程运行的不确定性,因此可能会出现以下问题:

  1.假设生产者线程刚向数据存储空间添加了数据的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程把信息的名称和上一个信息的内容联系到了一起;

  2.生产者生产了若干条数据,消费者才可以取数据,或者是,消费者取完一次数据后,还没等生产者放入新的数据,又重复取出了已取过的数据。

通过分析我们可知:

  第一个问题可以通过同步来解决,第二个问题就需要用到线程通信。生产者线程放入数据后,通知消费者线程取出数据,消费者线程取出数据后,通知生产者线程生产数据,这里用wait\notigy机制来实现。

Java代码

定义信息类

package thread;public class Info {private String name = "name";private String content = "content";//设置标志位,用来进行线程通信private boolean flag =true;/*** 设置消息,此处用到线程同步* @param name* @param content*/public synchronized void set(String name,String content){while (!flag){try {super.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.name=name; //设置名称try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}this.content=content; //设置内容flag =false; //设置标志位,表示现在生产停止,可以取走!}public synchronized void get(){while (flag){try {super.wait();} catch (InterruptedException e) {e.printStackTrace();}}try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(name +" --> " + content) ;flag  = true ;  // 改变标志位,表示可以生产super.notify();}}  

定义生产者

public class Producer implements Runnable {private Info info=null;public Producer(Info info){this.info=info;}@Overridepublic void run() {boolean flag = true ;   // 定义标记位for(int i=0;i<10;i++){if(flag){this.info.set("姓名--1","内容--1") ;    // 设置名称flag = false ;}else{this.info.set("姓名--2","内容--2") ;    // 设置名称flag = true ;}}}
}

定义消费者

public class Consumer implements Runnable {private Info info = null ;public Consumer(Info info){this.info = info ;}public void run(){for(int i=0;i<10;i++){this.info.get() ;}}public static void main(String[] args) {Info info = new Info(); // 实例化Info对象Producer pro = new Producer(info) ; // 生产者Consumer con = new Consumer(info) ; // 消费者new Thread(pro).start() ;//启动了生产者线程后,再启动消费者线程try{Thread.sleep(500) ;}catch(InterruptedException e){e.printStackTrace() ;}new Thread(con).start() ;}
}

 使用阻塞队列来实现相同功能

引入BlockingQueue

  任何有效的生产者-消费者问题解决方案都是通过控制生产者put()方法(生产资源)和消费者take()方法(消费资源)的调用来实现的,一旦你实现了对方法的阻塞控制,那么你将解决该问题。Java通过BlockingQueue提供了开箱即用的支持来控制这些方法的调用(一个线程创建资源,另一个消费资源)。java.util.concurrent包下的BlockingQueue接口是一个线程安全的可用于存取对象的队列

  

  BlockingQueue是一种数据结构支持一个线程往里存资源,另一个线程从里取资源。这正是解决生产者消费者问题所需要的,那么让我们开始解决该问题吧。

Java代码

消息类

public class InfoPlus {private String name = "name";private String content = "content";public InfoPlus(String name, String content) {this.name = name;this.content = content;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "InfoPlus{" +"name='" + name + '\'' +", content='" + content + '\'' +'}';}
}

生产者

import java.util.concurrent.BlockingQueue;public class ProducerPlus implements Runnable {private BlockingQueue<InfoPlus> queue;public ProducerPlus(BlockingQueue<InfoPlus> queue) {this.queue = queue;}@Overridepublic void run() {for (int i=0;i<10;i++){try {Thread.sleep(1000);queue.put(new InfoPlus("name"+i,"content"+i));} catch (InterruptedException e) {e.printStackTrace();}}}
}

消费者

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;public class ConsumerPlus implements Runnable{private BlockingQueue<InfoPlus> queue;public ConsumerPlus(BlockingQueue<InfoPlus> queue) {this.queue = queue;}public void run() {while (true) {try {System.out.println(this.queue.take());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {BlockingQueue<InfoPlus> blockingQueue = new LinkedBlockingDeque<>();ProducerPlus producerPlus = new ProducerPlus(blockingQueue);ConsumerPlus consumerPlus = new ConsumerPlus(blockingQueue);ConsumerPlus consumerPlus1 = new ConsumerPlus(blockingQueue);new Thread(producerPlus).start();new Thread(consumerPlus).start();new Thread(consumerPlus1).start();}
}

 

转载于:https://www.cnblogs.com/MrSaver/p/9409838.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

001.Linux开机启动过程

相关Linux启动过程解析&#xff0c;此作为通用启动参考&#xff1a; 转载于:https://www.cnblogs.com/itzgr/p/10285833.html

学习vim 从常用按键开始

撤销 u 前进 ctrl r移动 下一个单词 w 当前单词首或上个单词首 b 当前单词尾或上个单词尾 e ---- 大写就是忽略标点符号 行首行尾 $^ 查询 /word 下一个 n 上一个 Nv 可视化操作命令 删除操作 x 删除光标处的字符&#xff0c;向后删除 nx …

element ui 中 el-menu 如何添加链接router-link标签

在vue项目中&#xff0c;使用elementui 框架&#xff0c;做一个后台管理系统 在写左边菜单&#xff0c;菜用了&#xff0c;elementui 提供的组件 &#xff0c; el-menu 组件。但是组件没有链接&#xff0c;而我们知道添加链接使用router-link标签代码如下&#xff1a; <el-…

使用fastjson的parseObject方法将json字符串转换成Map 或者List

fastjson 转换成map HashMap<String,String> map JSON.parseObject(jsonStr,new TypeReference<HashMap<String,String>>() {}); fastjson 转换成list List<Person> list new ArrayList<Person>(); list JSON.parseArray(jasonArray.toStri…

【01】《正则表达式必知必会》(已看)(仅存放)

【01】《正则表达式必知必会》 共149页。扫描版&#xff0c;中文版。Sams Teach Yourselef Regular Expressions in 10 minutesBen Forta著。杨涛 翻译【】魔芋&#xff1a;这本书已经没有用了。内容已吸收。内容较为基础&#xff0c;也很全面。** 附件列表 链接&#xff1a;ht…

vue-cli脚手架的.babelrc文件

{// 此项指明&#xff0c;转码的规则"presets": [// env项是借助插件babel-preset-env&#xff0c;下面这个配置说的是babel对es6,es7,es8进行转码&#xff0c;并且设置amd,commonjs这样的模块化文件&#xff0c;不进行转码["env", {"modules": …

Java秒杀业务架构设计之路

Java秒杀业务架构设计之路

疑难杂症,逐个下药

用户登陆&#xff08;三次输错机会&#xff09;且每次输错误时显示剩余错误次数&#xff08;提示&#xff1a;使用字符串格式化&#xff09; 三次登录: 1.让用户输入三次的机会,错一次的时候就要询问用户是否要继续 2.分别判断用户名和密码,如果用户名错误就提示用户错误,如果是…

JS性能分析(测试代码运行时间)

console.time("timer"); for(var i0;i<10000;i){} console.timeEnd("timer"); timer: 0.274169921875ms转载于:https://www.cnblogs.com/smzd/p/10647455.html

jsonp原生js跨域拿新浪数据插件封装【可扩展】

//修改了一个bug,增加了手动释放垃圾 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-…

Ansible基本命令

Ansible安装完成之后就自带很多命令&#xff0c;其中较常用的有7个&#xff1a; ansibleansible-docansible-galaxyansible-initansible-playbookansible-pullansible-vaultansible ansible -h Usage: ansible <host-pattern> [options] 对本机执行一个命令&#xff1a; …

Java高并发高性能分布式框架从无到有微服务架构设计

Java高并发高性能分布式框架从无到有微服务架构设计

Makefile中几种赋值

延时变量&#xff0c;只有被使用时才展开定义 : 立即变量&#xff0c;定义时的赋值立即有效 ? 条件变量&#xff0c;当变量为空时才赋值 追加赋值转载于:https://www.cnblogs.com/smzd/p/10695962.html

线程的基本协作和生产者消费者

协作基础&#xff08;wait/notify&#xff09; Java的根父类是Object&#xff0c;Java在Object类而非Thread类中&#xff0c;定义了一些线程协作的基本方法&#xff0c;使得每个对象都可以调用这些方法&#xff0c;这些方法有两类&#xff0c;一类是wait&#xff0c;另一类是no…

L1-016 查验身份证

L1-016 查验身份证 &#xff08;15 分&#xff09;一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff…

什么是高并发,如何避免高并发

之前我将高并发的解决方法误认为是线程或者是队列可以解决&#xff0c;因为高并发的时候是有很多用户在访问&#xff0c;导致出现系统数据不正确、丢失数据现象&#xff0c;所以想到 的是用队列解决&#xff0c;其实队列解决的方式也可以处理&#xff0c;比如我们在竞拍商品、转…

.sync 修饰符的理解

正常 子组件&#xff1a; this.$emit(update:title, newTitle)父组件&#xff1a; <text-documentv-bind:title"doc.title"v-on:update:title"doc.title $event" ></text-document>简洁&#xff1a; <text-document v-bind:title.sync&quo…

L1-025 正整数A+B

题的目标很简单&#xff0c;就是求两个正整数A和B的和&#xff0c;其中A和B都在区间[1,1000]。稍微有点麻烦的是&#xff0c;输入并不保证是两个正整数。 输入格式&#xff1a; 输入在一行给出A和B&#xff0c;其间以空格分开。问题是A和B不一定是满足要求的正整数&#xff0c;…

到底多大才算高并发?

一、什么是高并发 定义&#xff1a; 高并发(High Concurrency)是使用技术手段使系统可以并行处理很多请求。关键指标&#xff1a; -响应时间(Response Time) -吞吐量(Throughput) -每秒查询率QPS(Query Per Second) -每秒事务处理量TPS(Transaction Per Second) -同时在…

eclipse安装maven插件

1、在线安装插件 a.打开eclipse&#xff0c;菜单“Help”-“Install New Software...” b.在Work with 地址栏输入&#xff1a;http://download.eclipse.org/releases/对应eclipse版本名称 c.在filter框中输入maven d.选择“Collaboration”-“m2e - Maven Integration for Ecl…