多线程笔记 - provider-consumer
通过多线程实现一个简单的生产者-消费者案例(笔记).
首先定义一个要生产消费的数据类 :
public class Data {
private String id;
private String name;
public Data(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Data{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
生产者首先需要一个装载数据的容器, 产生的数据, 需要往里面放.
public class Provider implements Runnable {
//1. 装载数据的容器
private BlockingQueue<Data> queue;
//2. 运行标志
private volatile boolean isRunning = true;
//3. 为数据产生id
private static AtomicInteger count = new AtomicInteger();
//4. 随机休眠
private static Random r = new Random();
public Provider(BlockingQueue queue){
this.queue = queue;
}
@Override
public void run() {
while (isRunning){
try {
//随机休眠, 模拟产生数据逻辑耗时
Thread.sleep(r.nextInt(100));
//产生一个数据id, 为了避免多线程产生的id重复, 所以这里使用 AtomicInteger
int id = count.incrementAndGet();
//创建数据
Data data = new Data(Integer.toString(id), "data" + id);
//打印创建日志
System.out.println( Thread.currentThread().getName() + " ++++++ " + id);
//将数据加载到容器中
if(!this.queue.offer(data, 1, TimeUnit.SECONDS)){
System.out.println(id + " 提交失败......");
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop(){
this.isRunning = false;
}
public void reset(){
this.isRunning = true;
}
}
消费者, 也需要知道数据存放的容器, 才能从里面拿取数据进行处理.
public class Consumer implements Runnable {
//1. 数据容器, 从中取数据进行消费
private BlockingQueue<Data> queue;
public Consumer(BlockingQueue<Data> queue){
this.queue = queue;
}
//随机休眠
private static Random r = new Random();
@Override
public void run() {
while (true){
try {
//从队列中取数据
Data data = this.queue.take();
//如果获取到的数据为空, 则不进行处理
if(data == null){
continue;
}
//随机休眠, 模拟消费数据逻辑处理耗时
Thread.sleep(r.nextInt(1000));
//打印消费日志
System.out.println( Thread.currentThread().getName() + " ------ " + data.getId());
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试方法:
public static void main(String[] args){
//BlockingQueue<Data> queue = new LinkedBlockingQueue<>(16);
BlockingQueue<Data> queue = new ArrayBlockingQueue<>(16);
List<Provider> providers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Provider p = new Provider(queue);
providers.add(p);
}
List<Consumer> consumers = new ArrayList<>();
for (int i = 0; i < 2; i++) {
Consumer c = new Consumer(queue);
consumers.add(c);
}
ExecutorService pool = Executors.newCachedThreadPool();
for (Provider provider : providers) {
pool.execute(provider);
}
for (Consumer consumer : consumers) {
pool.execute(consumer);
}
try {
Thread.sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
for (Provider provider : providers) {
provider.stop();
}
}
这里特意用了一个有界队列, 并且特意设置了生产者多于消费者.
打印日志:

+ 号代表产生了数据, 但是不一定加入到容器里了.
- 号代表消费成功, 数据从队列中删除
这里需要注意一个问题:
生产消费都是有速度的, 也就是说, 如果消费速度小于生产速度
1. 使用有界队列 - 会丢数据, 需要对这部分数据做特殊处理
2. 使用无界队列 - 可能会让电脑宕机, 数据积累越来越多, 导致内存不足, 卡死或者直接死机.
需要对应用场景进行分析, 才能决定使用哪种方式.
多线程笔记 - provider-consumer的更多相关文章
- 2016/1/25 多线程 作业 方法一 继承Thread 方法二 实现Runnable 多线程笔记
/* * 1,尝试定义一个继承Thread类的类,并覆盖run()方法, * 在run()方法中每隔100毫秒打印一句话.*/ package Stream; //方法一 继承Thread 实现多线程 ...
- Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)
1. 基础知识: Android(java)学习笔记61:多线程程序的引入 ~ Android(java)学习笔记76:多线程-定时器概述和使用
- dubbo 学习笔记 -- provider端
服务端的配置文件: provider.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...
- 如何理解springcloud微服务项目中,eureka,provider,consumer它们之间的关系?
eureka负责注册provider和consumer的服务信息 provider负责与数据库进行交互,实现数据持久化,并给consumer提供服务 consumer与前端交互,通过与Eureka同源 ...
- 这份java多线程笔记,你真得好好看看,我还没见过总结的这么全面的
1.线程,进程和多线程 1.程序:指指令和数据的有序集合,其本身没有任何意义,是一个静态的概念 2.进程:指执行程序的一次执行过程,是一个动态的概念.是系统资源分配的单位(注意:很多多线程是模拟出来的 ...
- iOS多线程笔记
在iOS开发中,有三种多线程处理方式: 1. 利用NSThread 2. NSOperation和NSOperationQueue 3. 利用GCD(Grand Central Dispatch) 使 ...
- Java基础知识强化之多线程笔记05:Java中继承thread类 与 实现Runnable接口的区别
1. Java中线程的创建有两种方式: (1)通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中. (2)通过实现Runnable接口,实例化Thread类. 2. ...
- QT多线程笔记
1.QT多线程涉及到主线程和子线程之间交互大量数据的时候,使用QThread并不方便,因为run()函数本身不能接受任何参数,因此只能通过信号和槽的交互来获取数据,如果只是单方面简单交互数据还过得去, ...
- Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗
1. Java程序运行原理: Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...
随机推荐
- synchronized底层实现
1.锁升级的过程 当多个线程同时竞争一个对象监视器时:当前对象结构中的mark word中是否是当前线程id,如果是则当前线程获得偏向锁. 如果不是,则通过CAS将当前线程id置换到mark word ...
- Linux系统终端session保持服务工具-Tmux
Tmux是非常流行的终端复用软件,通过一个终端登录远程主机并运行tmux后,在其中可以开启多个控制台而无需再“浪费”多余的终端来连接这台远程主机.相对于Screen,它更加先进:支持屏幕切分,而且具备 ...
- Java基础系列1:深入理解Java数据类型
Java基础系列1:深入理解Java数据类型 当初学习计算机的时候,教科书中对程序的定义是:程序=数据结构+算法,Java基础系列第一篇就聊聊Java中的数据类型. 本篇聊Java数据类型主要包括四个 ...
- Ubuntu16.04-Server固定静态IP
1. 查看IP信息-ifconfig 2.修改配置文件---sudo vim /etc/network/interfaces 修改为静态ip 配置说明: auto ens33:使用的网络接口 ifa ...
- Redhat6.7 切换Centos yum源
转自:http://inlhx.iteye.com/blog/2336729 RedHat 更换Yum源 1.检查yum包 rpm -qa |grep yum 2.删除自带包 rpm -aq | gr ...
- PYTHON经典算法-完美平方
问题描述: 给定一个正整数n,找到若干个完全平方数(例如:1,4,9),使得 它们的和等于n,完全平方数的个数最少. 问题示例: 给出n=12,返回3,因为12=4+4+4:给出n=13,返回2,因为 ...
- jenkins 与 gitlab 的持续集成
前言介绍 gitlab与jenkins的安装部署请参考之前的文章:这里介绍一下jenkins与gitlab结合的好处. gitlab可以自己实现CICD功能,jenkins也可以结合其他工具来实现CI ...
- 使用 web3D 技术的风力发电场展示
前言 风能是一种开发中的洁净能源,它取之不尽.用之不竭.当然,建风力发电场首先应考虑气象条件和社会自然条件.近年来,我国海上和陆上风电发展迅猛.海水.陆地为我们的风力发电提供了很好地质保障.正是 ...
- Kotlin Android项目静态检查工具的使用
Kotlin Android项目静态检查工具的使用 Kotlin Android项目可用的静态检查工具: Android官方的Lint, 第三方的ktlint和detekt. 静态检查工具 静态检查工 ...
- CSS 故障艺术
本文的主题是 Glitch Art,故障艺术. 什么是故障艺术?我们熟知的抖音的 LOGO 正是故障艺术其中一种表现形式.它有一种魔幻的感觉,看起来具有闪烁.震动的效果,很吸引人眼球. 故障艺术它模拟 ...