生产消费模式:多线程读写队列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 ...
随机推荐
- java基础05 选择结构
选择结构 public class Demo01Change { public static void main(String[] args) { /** * 实现等量的转换 */ int a = 5 ...
- linux中的周期调度器
2017-06-27 上篇文章简要介绍了Linux进程调度,以及结合源代码窥探了下CFS的调度实例.但是没有深入内部区分析调度下面的操作,比如就绪队列的维护以及进程时间的更新等.本节就这些问题做深入讨 ...
- linux系统centOS在虚拟机下的自定义安装
一 前戏 1.1在官网找到合适的版本,镜像文件 1.2安装VMware FF590-2DX83-M81LZ-XDM7E-MKUT4 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 ZC3 ...
- javascrpt 页面格式化页面
下面这个页面,格式化javaScript <html> <head> <title>JS格式化工具 </title> <meta http-equ ...
- 正则表达式验证合法的IP地址
IPv4地址 最初设计互联网络时,为了便于寻址和层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID.同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上的 ...
- python 添加进度条
安装: pip install tqdm使用: from tqdm import tqdm import time for i in tqdm(rang(10)): time.sleep(0.1)
- java堆结构和垃圾回收
JVM内存结构和垃圾回收一.JVM垃圾收集算法1.引用计数算法 每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收. 此方法简单,无法解决对象互相循环引用的问题 ...
- 细说PHP的FPM
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++基础概念++ C ...
- 无线路由MAC地址过滤安全可靠性讨论
无线路由MAC地址过滤安全可靠性讨论/如何实现,真的有效吗,如何防范 [内容导航] 什么是MAC地址过滤 突破MAC地址过滤步骤 捕获的无线客户端MAC地址 更改MAC地址来伪造身份 在W ...
- Get started on your own KD 8 custom colorway
The 2009 Summer time Nike Basketball revealed the Cheap KD 8 and revealed three MVP-inspired colors ...