堵塞队列,解决多线程中数据传输问题;
在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒;
常用的队列主要有以下两种:
先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能。从某种程度上来说这种队列也体现了一种公平性。
后进先出(LIFO):后插入队列的元素最先出队列,这种队列优先处理最近发生的事件。
下面两幅图演示了BlockingQueue的两个常见阻塞场景:
如上图所示:当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。
boolean add(E e); boolean offer(E e);//添加对象,不会堵塞线程 void put(E e) throws InterruptedException;//添加对象,若队列已满,则造成调用该方法的线程阻断,直到队列有空间再继续boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;//设定时间,超出时间,添加失败
E take() throws InterruptedException;//取走队列首位对象,若BlockingQueue为空,阻断进入等待状态直到
BlockingQueue有新的数据被加入 E poll(long timeout, TimeUnit unit)//在限定时间内取出队列头部对象,若超时则失败 throws InterruptedException;
int remainingCapacity(); boolean remove(Object o); public boolean contains(Object o); int drainTo(Collection<? super E> c);一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数),
通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。 int drainTo(Collection<? super E> c, int maxElements);
ArrayBlockingQueue:底层是数组的有界堵塞队列;
//默認非公平鎖 public ArrayBlockingQueue(int capacity) {
this(capacity, false); }
public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); }
成员变量:
数组items用来存放队列元素 final Object[] items;另外有个,另外notEmpty,notFull条件变量用来进行出入队的同步。
int takeIndex;//表示出隊元素下標
final ReentrantLock lock;//独占锁lock用来对出入队操作加锁,这导致同时只有一个线程可以访问入队出队 |
notEmpty,notFull条件变量用来进行出入队的同步
private final Condition notEmpty; private final Condition notFull;
从定义可知道并没有使用volatile修饰,这是因为访问这些变量使用都是在锁块内,并不存在可见性问题。
ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于LinkedBlockingQueue;
size方法加鎖,此時不能添加和刪除 |
public int size() { final ReentrantLock lock = this.lock; lock.lock(); try { return count; } finally { lock.unlock(); } }
https://blog.csdn.net/qq_23359777/article/details/70146778
http://wsmajunfeng.iteye.com/blog/1629354
final ReentrantLock lock;// |