ArrayBlockingQueue源码分析

   原文来自:https://blog.csdn.net/xin_jmail/article/details/26157971

ArrayBlockingQueue是一个由数组支持的有界阻塞队列,也是一个循环队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素,队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。
     这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。

    ArrayBlockingQueue创建的时候需要指定容量capacity(可以存储的最大的元素个数,因为它不会自动扩容)。其中一个构造方法为:

[java]  view plain  copy
  1. public ArrayBlockingQueue(int capacity, boolean fair) {  
  2.        if (capacity <= 0)  
  3.            throw new IllegalArgumentException();  
  4.        this.items = (E[]) new Object[capacity];  
  5.        lock = new ReentrantLock(fair);  
  6.        notEmpty = lock.newCondition();  
  7.        notFull =  lock.newCondition();  
  8.    }  

    ArrayBlockingQueue类中定义的变量有:

[java]  view plain  copy
  1. /** The queued items  */  
  2. private final E[] items;  
  3. /** items index for next take, poll or remove */  
  4. private int takeIndex;  
  5. /** items index for next put, offer, or add. */  
  6. private int putIndex;  
  7. /** Number of items in the queue */  
  8. private int count;  
  9. /** Main lock guarding all access */  
  10. private final ReentrantLock lock;  
  11. /** Condition for waiting takes */  
  12. private final Condition notEmpty;  
  13. /** Condition for waiting puts */  
  14. private final Condition notFull;  
使用数组items来存储元素,由于是循环队列,使用takeIndex和putIndex来标记put和take的位置。可以看到,该类中只定义了一个锁ReentrantLock,定义两个Condition对象:notEmputy和notFull,分别用来对take和put操作进行所控制。注:本文主要讲解put()和take()操作,其他方法类似。

put(E e)方法的源码如下。进行put操作之前,必须获得锁并进行加锁操作,以保证线程安全性。加锁后,若发现队列已满,则调用notFull.await()方法,如当前线程陷入等待。直到其他线程take走某个元素后,会调用notFull.signal()方法来激活该线程。激活之后,继续下面的插入操作。

[java]  view plain  copy
  1. /** 
  2.      * Inserts the specified element at the tail of this queue, waiting 
  3.      * for space to become available if the queue is full. 
  4.      * 
  5.      */  
  6.     public void put(E e) throws InterruptedException {  
  7.         //不能存放 null  元素  
  8.         if (e == nullthrow new NullPointerException();  
  9.         final E[] items = this.items;   //数组队列  
  10.         final ReentrantLock lock = this.lock;  
  11.         //加锁  
  12.         lock.lockInterruptibly();  
  13.         try {  
  14.             try {  
  15.                 //当队列满时,调用notFull.await()方法,使该线程阻塞。  
  16.                 //直到take掉某个元素后,调用notFull.signal()方法激活该线程。  
  17.                 while (count == items.length)  
  18.                     Full.await();  
  19.             } catch (InterruptedException ie) {  
  20.                 Full.signal(); // propagate to non-interrupted thread  
  21.                 throw ie;  
  22.             }  
  23.             //把元素 e 插入到队尾  
  24.             insert(e);  
  25.         } finally {  
  26.             //解锁  
  27.             lock.unlock();  
  28.         }  
  29.     }  
insert(E e) 方法如下:

[java]  view plain  copy
  1.   /** 
  2.    * Inserts element at current put position, advances, and signals. 
  3.    * Call only when holding lock. 
  4.    */  
  5.   private void insert(E x) {  
  6.       items[putIndex] = x;    
  7. //下标加1或者等于0  
  8.       putIndex = inc(putIndex);  
  9.       ++count;  //计数加1  
  10. //若有take()线程陷入阻塞,则该操作激活take()线程,继续进行取元素操作。  
  11. //若没有take()线程陷入阻塞,则该操作无意义。  
  12.       Empty.signal();  
  13.   }  
  14.   
  15. **  
  16.    * Circularly increment i.  
  17.    */  
  18.   final int inc(int i) {  
  19. //此处可以看到使用了循环队列  
  20.       return (++i == items.length)? 0 : i;  
  21.   }  
take()方法代码如下。take操作和put操作相反,故不作详细介绍。

[java]  view plain  copy
  1. public E take() throws InterruptedException {  
  2.         final ReentrantLock lock = this.lock;  
  3.         lock.lockInterruptibly();  //加锁  
  4.         try {  
  5.             try {  
  6.                 //当队列空时,调用notEmpty.await()方法,使该线程阻塞。  
  7.                 //直到take掉某个元素后,调用notEmpty.signal()方法激活该线程。  
  8.                 while (count == 0)  
  9.                     Empty.await();  
  10.             } catch (InterruptedException ie) {  
  11.                 Empty.signal(); // propagate to non-interrupted thread  
  12.                 throw ie;  
  13.             }  
  14.             //取出队头元素  
  15.             E x = extract();  
  16.             return x;  
  17.         } finally {  
  18.             lock.unlock();  //解锁  
  19.         }  
  20.     }  
extract() 方法如下:

[java]  view plain  copy
  1. /** 
  2.      * Extracts element at current take position, advances, and signals. 
  3.      * Call only when holding lock. 
  4.      */  
  5.     private E extract() {  
  6.         final E[] items = this.items;  
  7.         E x = items[takeIndex];  
  8.         items[takeIndex] = null;  
  9.         takeIndex = inc(takeIndex);  
  10.         --count;  
  11.         Full.signal();  
  12.         return x;  
  13.     }  
小结:进行put和take操作,共用同一个锁对象。也即是说,put和take无法并行执行!两个Condition来进行通信。
数据治理是确保数据准确性、可靠性、安全性、可用性和完整性的体系和框架。它定义了组织内部如何使用、存储、保护和共享数据的规则和流程。数据治理的重要性随着数字化转型的加速而日益凸显,它能够提高决策效率、增强业务竞争力、降低风险,并促进业务创新。有效的数据治理体系可以确保数据在采集、存储、处理、共享和保护等环节的合规性和有效性。 数据质量管理是数据治理中的关键环节,它涉及数据质量评估、数据清洗、标准化和监控。高质量的数据能够提升业务决策的准确性,优化业务流程,并挖掘潜在的商业价值。随着大数据和人工智能技术的发展,数据质量管理在确保数据准确性和可靠性方面的作用愈发重要。企业需要建立完善的数据质量管理和校验机制,并通过数据清洗和标准化提高数据质量。 数据安全与隐私保护是数据治理中的另一个重要领域。随着数据量的快速增长和互联网技术的迅速发展,数据安全与隐私保护面临前所未有的挑战。企业需要加强数据安全与隐私保护的法律法规和技术手段,采用数据加密、脱敏和备份恢复等技术手段,以及加强培训和教育,提高安全意识和技能水平。 数据流程管理与监控是确保数据质量、提高数据利用率、保护数据安全的重要环节。有效的数据流程管理可以确保数据流程的合规性和高效性,而实时监控则有助于及时发现并解决潜在问题。企业需要设计合理的数据流程架构,制定详细的数据管理流程规范,并运用数据审计和可视化技术手段进行监控。 数据资产管理是将数据视为组织的重要资产,通过有效的管理和利用,为组织带来经济价值。数据资产管理涵盖数据的整个生命周期,包括数据的创建、存储、处理、共享、使用和保护。它面临的挑战包括数据量的快速增长、数据类型的多样化和数据更新的迅速性。组织需要建立完善的数据管理体系,提高数据处理和分析能力,以应对这些挑战。同时,数据资产的分类与评估、共享与使用规范也是数据资产管理的重要组成部分,需要制定合理的标准和规范,确保数据共享的安全性和隐私保护,以及建立合理的利益分配和权益保障机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值