生产消费模式:多线程读写队列ConcurrentQueue
需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子。
直接上代码,看下实现:
// 初始化列队缓冲区 队列大小为100
IDataCollection<List<T>> queue = new QueueCollection<List<T>>(); //开启X个后台任务,读取RabbitMQ队列信息, 把列队信息插入缓冲区队列
var count = ;
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Producer<List<T>>(queue).Start(new RabbitSource<List<T>>().Get));
} //开启X个后台任务,主动获取数据库数据,作为数据生产者,插入到缓冲区队列,
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Producer<List<T>>(queue).Start(new DatabaseSource<List<T>>().Get));
} //开启X个后台任务,主动获取读取缓冲区列队,作为数据消息者,把数据插入到ES库,
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Customer<List<T>>(queue).Start(new Elastic().Insert));
}
队列我们采用线程安全的ConcurrentQueue队列:
/// <summary>
/// 缓冲区队列
/// ConcurrentQueue线程安全,不用考虑锁的问题
/// </summary>
public class QueueCollection<T> :IDataCollection<T>
{
//队列最大值
private int _maxSize; /// <summary>
/// 线程安全的队列
/// </summary>
private ConcurrentQueue<T> _queue; public QueueCollection(int maxSize)
{
this._maxSize = maxSize;
_queue = new ConcurrentQueue<T>();
} public bool isPopWaiting()
{
return !_queue.Any();
} public bool isPushWaiting()
{
return this._maxSize == _queue.Count;
} public T Pop()
{
T _obj = default(T);
if (!_queue.IsEmpty)
_queue.TryDequeue(out _obj); return _obj;
} public void Push(T t)
{
if (this._maxSize > _queue.Count)
{
_queue.Enqueue(t);
}
}
}
如果我们不使用这个队列,只要满足IDataCollection接口,也可以进行替换:
public interface IDataCollection<T>
{
/// <summary>
/// 插入数据
/// </summary>
/// <param name="t"></param>
void Push(T t); /// <summary>
/// 取出数据
/// </summary>
/// <returns></returns>
T Pop(); /// <summary>
/// 是否插入数据等待
/// </summary>
/// <returns></returns>
bool isPushWaiting(); /// <summary>
/// 是否取出数据等待
/// </summary>
/// <returns></returns>
bool isPopWaiting(); }
生产者:
public class Producer<T> : ITransientDependency
{
private int sleep; private IDataCollection<T> bufferQueue; public Producer(IDataCollection<T> queue)
{
sleep = ;
bufferQueue = queue;
} public void Start(Action<Action<T>> methodCall)
{
//入队
methodCall((bills) =>
{
this.Enqueue(bills);
});
} private void Enqueue(T t)
{
var isWaiting = true; while (isWaiting)
{
if (!bufferQueue.isPushWaiting())
{
this.bufferQueue.Push(t);
isWaiting = false;
}
else
{
//生产者等待时间
Thread.Sleep(sleep);
}
}
}
}
消费者:
/// <summary>
/// 消费者
/// </summary>
public class Customer<T>
{
//产品缓存队列
private IDataCollection<T> _queue; //消费者等待时间
private int Spead = ;//消费者等待时间 public Customer(IDataCollection<T> queue)
{
this._queue = queue;
} public void Start(Action<T> method)
{
while (true)
{
if (!_queue.isPopWaiting())
{
T box = this._queue.Pop(); method(box);
}
else
{
Thread.Sleep(Spead);
}
}
}
}
方法委托,也写了个基类,其实意义并不大,只是为了规范, 防止方法命名随意起。
public interface IDataSource<T>
{
void Get(Action<T> func);
}
最后,在DataSource的get方法中,调用 func即可。
生产消费模式:多线程读写队列ConcurrentQueue的更多相关文章
- 使用C#的泛型队列Queue实现生产消费模式
本篇体验使用C#的泛型队列Queue<T>实现生产消费模式. 如果把生产消费想像成自动流水生产线的话,生产就是流水线的物料,消费就是某种设备对物料进行加工的行为,流水线就是队列. 现在,要 ...
- 使用Condition实现多线程之间调用(生产消费模式)
一,object 类的wait(),notify()和notifyAll() Java 线程类也是一个object 类,它的实例都继承自java.lang.Thread 或其子类.wait(),not ...
- Java的多线程实现生产/消费模式
Java的多线程实现生产/消费模式 在Java的多线程中,我们经常使用某个Java对象的wait(),notify()以及notifyAll() 方法实现多线程的通讯,今天就使用Java的多线程实现生 ...
- 异步简析之BlockingCollection实现生产消费模式
目前市面上有诸多的产品实现队列功能,比如Redis.MemCache等... 其实c#中也有一个基础的集合类专门用来实现生产/消费模式 (生产模式还是建议使用Redis等产品) 下面是官方的一些资料和 ...
- SQLite多线程读写实践及常见问题总结
多线程读写 SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagen ...
- Java多线程 阻塞队列和并发集合
转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...
- JAVA多线程读写文件范例
在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址.如果有知情者,烦请帖出地址,我在此文上加入 ...
- c# 高效的线程安全队列ConcurrentQueue
c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...
- 为什么多线程读写 shared_ptr 要加锁?
https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...
随机推荐
- Python 之网络编程
# 流程描述: # # 1. 服务器根据地址类型(ipv4, ipv6), socket类型, 协议创建socket; # # 2. 服务器为socket绑定ip地址和端口号; # # 3. 服务器s ...
- Web项目管理工具精选(下)
原文:Web项目管理工具精选(下) 我们在上篇中已推介『代码管理.任务管理.支付工具.数据记录.Dashboard Analytics.客户支持』六个方面的工具.本文将介绍剩下七类工具. A/B测试 ...
- vue状态管理器(用户登录简单应用)
技术点:通过vue状态管理器,对已经登录的用户显示不同的页面: 一 vue之状态管理器应用 主要用来存储cookie信息 与vue-cookies一起使用 安装:npm install vue-co ...
- 如何查看java class文件的jdk版本
方法1: 用二进制的查看方式打开该class文件,参考如下: 只看第一行数据,前面8个字节CA FE BA BE 是固定的,之后4个字节00 00 是次版本号,次版本号后面的4个字节(00 33) ...
- 【开发者笔记】冒泡排序过程呈现之java内置GUI表示
自己玩玩写写,排序的过程多么有趣,特别是把看着电脑吧一堆乱七八糟的数据排成有序组合的时候,看起来贼舒服,特别是强迫症患者.好了,话不多说上代码,也算是自己记录一下吧,没有什么技术含量但个人感觉比较有趣 ...
- NAND flash学习所获----(Zac)
Nand Falsh外围电路:peripheral circuit 1.Nand flash里至少有2个state Machine(controller),即2个主控. 一个主控:负责处理前端事情. ...
- linux根文件系统 /etc/resolv.conf 文件详解(转)
大家好,今天51开源给大家介绍一个在配置文件,那就是/etc/resolv.conf.很多网友对此文件的用处不太了解.其实并不复杂,它是DNS客户机配置文件,用于设置DNS服务器的IP地址及DNS域名 ...
- FAQs on Android
@1: Environment Setup Ubuntu 14.04 32bits 1. Call Requires API level 11 (current min is 8) Android. ...
- docker——镜像(image)
镜像相关命令一览表: docker images docker tag docker inspect docker history docker search docker pull/push doc ...
- mysql数据库从删库到跑路之mysql完整性约束
一 介绍 约束条件与数据类型的宽度一样,都是可选参数 作用:用于保证数据的完整性和一致性主要分为: PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录 FOREIGN KEY ...