服务器端利器--双缓冲队列

http://rrsongzi-gmail-com.iteye.com/blog/696627

传统队列是生产者线程和消费者线程从同一个队列中存取数据,必然需要互斥访 问,在互相同步等待中浪费了宝贵的时间,使队列吞吐量受影响。双缓冲队使用两个队列,将读写分离,一个队列专门用来读,另一个专门用来写,当读队列空或写 队列满时将两个队列互换。这里为了保证队列的读写顺序,当读队列为空且写队列不为空时候才允许两个队列互换。

经过测试性能较JDK自带的queue的确有不小提高。


测试是和JDK6中性能最高的阻塞Queue:java.util.concurrent.ArrayBlockingQueue做比较,这个队列是环形队列的实现方式,性能还算不错,不过我们的目标是没有最好,只有更好。
测试场景:
起若干个生产者线程,往Queue中放数据,起若干个消费者线程从queue中取数据,统计每个消费者线程取N个数据的平均时间。
数据如下:
场景1 
生产者线程数:1
消费者线程数:1
Queue容量:5w
取元素个数:1000w
JDK ArrayBlockingQueue用时平均为:  5,302,938,177纳秒
双缓冲队列用时平均为:                      5,146,302,116纳秒
相差大概160毫秒

场景2: 
生产者线程数:5
消费者线程数:4
Queue容量:5w
取元素个数:1000w
JDK ArrayBlockingQueue用时平均为:  32,824,744,868纳秒
双缓冲队列用时平均为:                      20,508,495,221纳秒
相差大概12.3秒

可见在生产者消费者都只有一个的时候存和取的同步冲突比较小,双缓冲队列
优势不是很大,当存取线程比较多的时候优势就很明显了。

 

队列主要方法如下:

Java代码   收藏代码
  1. <span style="font-size: small;">/** 
  2.  *  
  3.  * CircularDoubleBufferedQueue.java 
  4.  * 囧囧有神 
  5.  * @param <E>2010-6-12 
  6.  */  
  7. public class CircularDoubleBufferedQueue<E> extends AbstractQueue<E>  
  8. implements BlockingQueue<E>, java.io.Serializable  
  9. {  
  10.     private static final long serialVersionUID = 1L;  
  11.     private Logger logger =   Logger.getLogger(CircularDoubleBufferedQueue.class.getName());  
  12.   
  13.     /** The queued items  */  
  14.     private final E[] itemsA;  
  15.     private final E[] itemsB;  
  16.       
  17.     private ReentrantLock readLock, writeLock;  
  18.     private Condition notEmpty;  
  19.     private Condition notFull;  
  20.     private Condition awake;  
  21.       
  22.       
  23.     private E[] writeArray, readArray;  
  24.     private volatile int writeCount, readCount;  
  25.     private int writeArrayHP, writeArrayTP, readArrayHP, readArrayTP;  
  26.       
  27.       
  28.     public CircularDoubleBufferedQueue(int capacity)  
  29.     {  
  30.         if(capacity<=0)  
  31.         {  
  32.             throw new IllegalArgumentException("Queue initial capacity can't less than 0!");  
  33.         }  
  34.           
  35.         itemsA = (E[])new Object[capacity];  
  36.         itemsB = (E[])new Object[capacity];  
  37.   
  38.         readLock = new ReentrantLock();  
  39.         writeLock = new ReentrantLock();  
  40.           
  41.         notEmpty = readLock.newCondition();  
  42.         notFull = writeLock.newCondition();  
  43.         awake = writeLock.newCondition();  
  44.           
  45.         readArray = itemsA;  
  46.         writeArray = itemsB;  
  47.     }  
  48.       
  49.     private void insert(E e)  
  50.     {  
  51.         writeArray[writeArrayTP] = e;  
  52.         ++writeArrayTP;  
  53.         ++writeCount;  
  54.     }  
  55.       
  56.     private E extract()  
  57.     {  
  58.         E e = readArray[readArrayHP];  
  59.         readArray[readArrayHP] = null;  
  60.         ++readArrayHP;  
  61.         --readCount;  
  62.         return e;  
  63.     }  
  64.   
  65.       
  66.     /** 
  67.      *switch condition:  
  68.      *read queue is empty && write queue is not empty 
  69.      *  
  70.      *Notice:This function can only be invoked after readLock is  
  71.          * grabbed,or may cause dead lock 
  72.      * @param timeout 
  73.      * @param isInfinite: whether need to wait forever until some other 
  74.      * thread awake it 
  75.      * @return 
  76.      * @throws InterruptedException 
  77.      */  
  78.     private long queueSwitch(long timeout, boolean isInfinite) throws InterruptedException  
  79.     {  
  80.         writeLock.lock();  
  81.         try  
  82.         {  
  83.             if (writeCount <= 0)  
  84.             {  
  85.                 logger.debug("Write Count:" + writeCount + ", Write Queue is empty, do not switch!");  
  86.                 try  
  87.                 {  
  88.                     logger.debug("Queue is empty, need wait....");  
  89.                     if(isInfinite && timeout<=0)  
  90.                     {  
  91.                         awake.await();  
  92.                         return -1;  
  93.                     }  
  94.                     else  
  95.                     {  
  96.                         return awake.awaitNanos(timeout);  
  97.                     }  
  98.                 }  
  99.                 catch (InterruptedException ie)  
  100.                 {  
  101.                     awake.signal();  
  102.                     throw ie;  
  103.                 }  
  104.             }  
  105.             else  
  106.             {  
  107.                 E[] tmpArray = readArray;  
  108.                 readArray = writeArray;  
  109.                 writeArray = tmpArray;  
  110.   
  111.                 readCount = writeCount;  
  112.                 readArrayHP = 0;  
  113.                 readArrayTP = writeArrayTP;  
  114.   
  115.                 writeCount = 0;  
  116.                 writeArrayHP = readArrayHP;  
  117.                 writeArrayTP = 0;  
  118.                   
  119.                 notFull.signal();  
  120.                 logger.debug("Queue switch successfully!");  
  121.                 return -1;  
  122.             }  
  123.         }  
  124.         finally  
  125.         {  
  126.             writeLock.unlock();  
  127.         }  
  128.     }  
  129.   
  130.     public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException  
  131.     {  
  132.         if(e == null)  
  133.         {  
  134.             throw new NullPointerException();  
  135.         }  
  136.           
  137.         long nanoTime = unit.toNanos(timeout);  
  138.         writeLock.lockInterruptibly();  
  139.         try  
  140.         {  
  141.             for (;;)  
  142.             {  
  143.                 if(writeCount < writeArray.length)  
  144.                 {  
  145.                     insert(e);  
  146.                     if (writeCount == 1)  
  147.                     {  
  148.                         awake.signal();  
  149.                     }  
  150.                     return true;  
  151.                 }  
  152.                   
  153.                 //Time out  
  154.                 if(nanoTime<=0)  
  155.                 {  
  156.                     logger.debug("offer wait time out!");  
  157.                     return false;  
  158.                 }  
  159.                 //keep waiting  
  160.                 try  
  161.                 {  
  162.                     logger.debug("Queue is full, need wait....");  
  163.                     nanoTime = notFull.awaitNanos(nanoTime);  
  164.                 }  
  165.                 catch(InterruptedException ie)  
  166.                 {  
  167.                     notFull.signal();  
  168.                     throw ie;  
  169.                 }  
  170.             }  
  171.         }  
  172.         finally  
  173.         {  
  174.             writeLock.unlock();  
  175.         }  
  176.     }  
  177.   
  178.     public E poll(long timeout, TimeUnit unit) throws InterruptedException  
  179.     {  
  180.         long nanoTime = unit.toNanos(timeout);  
  181.         readLock.lockInterruptibly();  
  182.           
  183.         try  
  184.         {  
  185.             for(;;)  
  186.             {  
  187.                 if(readCount>0)  
  188.                 {  
  189.                     return extract();  
  190.                 }  
  191.                   
  192.                 if(nanoTime<=0)  
  193.                 {  
  194.                     logger.debug("poll time out!");  
  195.                     return null;  
  196.                 }  
  197.                 nanoTime = queueSwitch(nanoTime, false);  
  198.             }  
  199.         }  
  200.         finally  
  201.         {  
  202.             readLock.unlock();  
  203.         }  
  204.     }  
  205.   
  206. }

实现多个读线程,一个写线程,并有一定的实时性和并发性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《neo4j权威指南-图数据库-大数据时代的新利器.pdf》是一本介绍Neo4j图数据库的权威指南。Neo4j是一种高性能、可扩展的图数据库,它能够处理大规模复杂数据,并提供了强大的查询和分析功能。 该书结构清晰,内容详细全面。首先介绍了图数据库的概念和基本原理,然后详细讲解了Neo4j的安装与配置。接下来,书中介绍了Neo4j图数据库的基本操作,包括数据的创建、删除、更新和查询等。 除了基本操作,该书还介绍了Neo4j的高级功能和应用场景。比如,如何构建复杂的图结构、如何优化查询性能以及如何进行数据的分析和可视化等。同时,书中也介绍了Neo4j与其他大数据工具(如Hadoop、Spark等)的集成方法。 这本书的优点在于,它不仅仅是一本理论性的指南,更注重实际应用。书中通过大量的示例和案例,让读者能够更好地理解Neo4j的用法和原理,并且能够在实际项目中灵活应用。 总而言之,该书是一本非常实用的图数据库指南,对于想要学习和应用Neo4j的人来说是一本不可或缺的参考书。无论是对于图数据库的初学者,还是对于有经验的开发者和数据分析师,这本书都能够提供很大的帮助。阅读它能够帮助读者更深入地理解和应用Neo4j图数据库,从而在大数据时代中获得新的利器。 ### 回答2: 《neo4j权威指南-图数据库-大数据时代的新利器.pdf》是一本介绍Neo4j图数据库的权威指南。Neo4j是一种基于图模型的高性能、高可伸缩性的数据库管理系统,它的出现使得处理大数据变得更加方便和高效。 这本指南首先介绍了图数据库的概念和基本知识,包括图的数据结构、节点、关系等。然后详细介绍了如何使用Neo4j进行图数据建模,包括节点和关系的创建、属性的定义、查询语言的使用等。 接着,指南介绍了Neo4j的高级功能和特性,如图算法、图遍历、索引和约束等。这些功能可以帮助用户更加灵活地处理和分析图数据,并从中获取有用的信息。 此外,指南还介绍了Neo4j在大数据时代的应用场景,包括社交网络分析、推荐系统、网络安全等。图数据库的优势在这些应用中得到了充分展示,为用户提供了更加高效和快速的数据处理方法。 总的来说,《neo4j权威指南-图数据库-大数据时代的新利器.pdf》是一本详细介绍Neo4j图数据库的权威指南,对初学者提供了宝贵的知识和实践经验,同时也为有经验的用户提供了更多高级功能和应用场景的深入探讨。无论是对于学习者还是开发者来说,这本指南都是一本不可或缺的参考书。 ### 回答3: 《Neo4j权威指南-图数据库-大数据时代的新利器》是一本介绍Neo4j图数据库的权威指南。图数据库是一种以图形的形式存储和处理数据的数据库系统,与传统的关系型数据库相比,可以更好地处理复杂的关系和连接。 本书首先介绍了图数据库的基本概念和特点,探讨了为什么图数据库在大数据时代成为新的利器。随着互联网的快速发展和数据的爆炸式增长,传统的数据库已经无法满足对数据的高效查询和分析的需求,而图数据库作为一种新型数据库技术,能够有效解决这些问题。 接着,本书详细介绍了Neo4j图数据库的特点、架构和基本操作。Neo4j是目前最流行的图数据库之一,它提供了一个高效、灵活和可扩展的图数据库解决方案。读者可以通过本书学习如何安装、配置和使用Neo4j,并掌握Cypher查询语言进行数据的查询和分析。此外,本书还介绍了图数据库的关键技术,如图算法和图分析,帮助读者充分发挥图数据库在数据挖掘和机器学习等领域的优势。 最后,本书还涵盖了Neo4j在实际应用中的案例和经验。通过实际的案例分析,读者可以了解如何使用Neo4j解决实际的业务问题,并掌握在实际项目中如何优化和调优Neo4j数据库。 总之,《Neo4j权威指南-图数据库-大数据时代的新利器》是一本全面而深入的图数据库入门指南,对于想要了解和使用图数据库的读者来说是一本非常实用的参考书。无论是数据库开发人员、数据科学家还是大数据分析师,都可以从本书中获得宝贵的知识和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值