需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子。

直接上代码,看下实现:

            // 初始化列队缓冲区 队列大小为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的更多相关文章

  1. 使用C#的泛型队列Queue实现生产消费模式

    本篇体验使用C#的泛型队列Queue<T>实现生产消费模式. 如果把生产消费想像成自动流水生产线的话,生产就是流水线的物料,消费就是某种设备对物料进行加工的行为,流水线就是队列. 现在,要 ...

  2. 使用Condition实现多线程之间调用(生产消费模式)

    一,object 类的wait(),notify()和notifyAll() Java 线程类也是一个object 类,它的实例都继承自java.lang.Thread 或其子类.wait(),not ...

  3. Java的多线程实现生产/消费模式

    Java的多线程实现生产/消费模式 在Java的多线程中,我们经常使用某个Java对象的wait(),notify()以及notifyAll() 方法实现多线程的通讯,今天就使用Java的多线程实现生 ...

  4. 异步简析之BlockingCollection实现生产消费模式

    目前市面上有诸多的产品实现队列功能,比如Redis.MemCache等... 其实c#中也有一个基础的集合类专门用来实现生产/消费模式 (生产模式还是建议使用Redis等产品) 下面是官方的一些资料和 ...

  5. SQLite多线程读写实践及常见问题总结

    多线程读写 SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagen ...

  6. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  7. JAVA多线程读写文件范例

    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址.如果有知情者,烦请帖出地址,我在此文上加入 ...

  8. c# 高效的线程安全队列ConcurrentQueue

    c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...

  9. 为什么多线程读写 shared_ptr 要加锁?

    https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...

随机推荐

  1. Python高级特性(3): Classes和Metaclasses(转)

    原文:Python高级特性(3): Classes和Metaclasses 类和对象 类和函数一样都是Python中的对象.当一个类定义完成之后,Python将创建一个“类对象”并将其赋值给一个同名变 ...

  2. ovn-kubernetes安装指南

    Master节点的安装 1.首先在master节点安装ovs和ovn: #!/bin/bash sudo apt-get install openvswitch-common openvswitch- ...

  3. sql之密码保存

    HashBytes (Transact-SQL) 其他版本   返回其输入的 MD2.MD4.MD5.SHA 或 SHA1 哈希值.  Transact-SQL 语法约定 语法         Has ...

  4. 004-hadoop家族概述

    hadoop家族 名称 简介   Hadoop 分布式基础架构 Hadoop的框架最核心的设计就是:HDFS和MapReduce.HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了 ...

  5. Java权威编码规范

    一.编程规约 (一) 命名规约 1. [强制] 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束. 反例: _nam / __name / $Object / name_  / ...

  6. ORACLE USERENV函数

    ORACLE USERENV函数 USERENV返回关于当前会话的信息.此信息可以用于编写一个应用程序特定的审计跟踪表或确定特定于语言的角色目前使用的会话. 参数 功能 CLINET_INFO 返回最 ...

  7. docker镜像上传到阿里云

    目前上传本地镜像到网上有多种途径,一个是上传到hub上,一个是阿里云镜像仓库,还要其他服务器. 上传到hub上实在是太慢了,我的服务器用的是阿里云,所以选择上传到阿里云镜像仓库中. 前提条件:linu ...

  8. H5移动端的一些坑、、、

    H5项目常见问题及注意事项 Meta基础知识: H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 //一.HTML页面结构 <meta name="viewport" co ...

  9. 安卓和ios的区别

    安卓不闪退,会卡死,有几率复活,也有可能要强制重启,iOS默认闪退,强制重启的几率小很多. 总的来说,如果要深层次挖掘Android的漏洞就要明白linux内核安全,如果要挖身深层次挖掘iOS的漏洞就 ...

  10. 《Unity3D》通过对象池模式,管理场景中的元素

    池管理类有啥用? 在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹.子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条.文字等等 这些元素共同的特性是:存在固定生命周期,使 ...