死磕java集合之ArrayBlockingQueue源码分析

  

问题

  

(1)之间的实现方式?

  

(2)之间是否需要扩容?

  

(3)之间有什么缺点吗?

  

简介

  

ArrayBlockingQueue是java并发包下一个以数组实现的阻塞队列,它是线程安全的,至于是否需要扩容,请看下面的分析。

  

队列

  

队列,是一种线性表,它的特点是先进先出,又叫FIFO,就像我们平常排队一样,先到先得,即先进入队列的人先出队。

  

源码分析

  

主要属性

  
 <代码类="语言java ">//使用数组存储元素
  最终对象[]项目;//取元素的指针
  int takeIndex;//放元素的指针
  int putIndex;//元素数量
  int数;//保证并发访问的锁
  最后ReentrantLock锁;//非空条件
  私人notEmpty最终条件;//非满条件
  私人notFull最终条件; 
  

通过属性我们可以得出以下几个重要信息:

  

(1)利用数组存储元素;

  

(2)通过放指针和取指针来标记下一次操作的位置;

  

(3)利用重入锁来保证并发安全;

  

主要构造方法

  
 <代码类="语言java ">公共ArrayBlockingQueue (int能力){
  这(容量、假);
  }
  
  公共ArrayBlockingQueue (int能力,布尔公平){
  如果(能力& lt;=0)
  把新IllegalArgumentException ();//初始化数组
  这一点。项=新对象(能力);//创建重入锁及两个条件
  锁=新的ReentrantLock(公平);
  notEmpty=lock.newCondition ();
  notFull=lock.newCondition ();
  } 
  

通过构造方法我们可以得出以下两个结论:

  

(1) ArrayBlockingQueue初始化时必须传入容量,也就是数组的大小;

  

(2)可以通过构造方法控制重入锁的类型是公平锁还是非公平锁;

  

入队

  

入队有四个方法,它们分别是添加(E E),提供(E E),把(E E),提供(E E,长时间超时,TimeUnit unit),它们有什么区别呢?

  
 <代码类="语言java ">公共逻辑加(E E) {//调用父类的add (e)方法
  返回super.add (e);
  }//super.add (e)
  公共逻辑加(E E) {//调用提供(e)如果成功返回真,如果失败抛出异常
  如果(提供(e))
  返回true;
  其他的
  把新IllegalStateException(“队列已满”);
  }
  
  公共布尔提供(E E) {//元素不可为空
  checkNotNull (e);
  最后ReentrantLock锁=this.lock;//加锁
  lock.lock ();
  尝试{
  如果(count==items.length)//如果数组满了就返回错误的
  返回错误;
  其他{//如果数组没满就调用入队方法并返回现实
  排队(e);
  返回true;
  }
  最后}{//解锁
  lock.unlock ();
  }
  }
  
  公共空间把(E E)抛出InterruptedException {
  checkNotNull (e);
  最后ReentrantLock锁=this.lock;//加锁,如果线程中断了抛出异常
  lock.lockInterruptibly ();
  尝试{//如果数组满了,使用notFull等待//notFull等待的意思是说现在队列满了//只有取走一个元素后,队列才不满//然后唤醒notFull,然后继续现在的逻辑//这里之所以使用,而不是如果//是因为有可能多个线程阻塞在锁上//即使唤醒了可能其它线程先一步修改了队列又变成满的了//这时候需要再次等待
  而(count==items.length)
  notFull.await ();//入队
  排队(e);
  最后}{//解锁
  lock.unlock ();
  }
  }
  
  公共布尔提供(E E,长时间超时,TimeUnit单元)
  抛出InterruptedException {
  checkNotNull (e);
  长nano=unit.toNanos(超时);
  最后ReentrantLock锁=this.lock;//加锁
  lock.lockInterruptibly ();
  尝试{//如果数组满了,就阻塞nano纳秒//如果唤醒这个线程时依然没有空间且时间到了就返回错误的
  而(count==items.length) {
  如果(nano & lt;=0)
  返回错误;
  nano=notFull.awaitNanos (nano);
  }//入队
  排队(e);
  返回true;
  最后}{//解锁
  lock.unlock ();
  }
  }
  
  私人空间排队(E x) {
  最终对象[]项=this.items;//把元素直接放在放指针的位置上
  项目[putIndex]=x;//如果放指针到数组尽头了,就返回头部
  如果(+ + putIndex==items.length)
  putIndex=0;//数量加1
  数+ +;//唤醒notEmpty,因为入队了一个元素,所以肯定不为空了
  notEmpty.signal ();
  } 
  

(1)添加(e)时如果队列满了则抛出异常;

  

(2)提供(e)时如果队列满了则返回假;

  

(3)把(e)时如果队列满了则使用notFull等待;

  

(4)提供(e、超时、单元)时如果队列满了则等待一段时间后如果队列依然满就返回假;

死磕java集合之ArrayBlockingQueue源码分析