五 、子类 LinkedBlockingQueue
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
=== 点击查看top目录 ===
5.1 变量
变量 | 备注 |
---|
private final int capacity | queue 容量,默认Integer.MAX_VALUE,注意是 final类型 |
private final AtomicInteger count | queue内数量,CAS |
transient Node head; | queue头 ,注意 transient |
private transient Node last; | queue的尾巴,注意 transient |
private final ReentrantLock takeLock | 取锁take锁 |
private final Condition notEmpty = takeLock.newCondition(); | queue非空Condition |
private final ReentrantLock putLock | 塞锁put锁 |
private final Condition notFull = putLock.newCondition(); | queue非满Condition |
=== 点击查看top目录 ===
5.2 方法
方法 | 备注 |
---|
public int size() | CAS获取queue数量 |
public int remainingCapacity() | queue 剩余容量 |
public void put(E e) throws InterruptedException | blocking 等待 put 进去元素 |
public boolean offer(E e, long timeout, TimeUnit unit) | blocking put 进去元素 尝试一段时间 |
public boolean offer(E e) | blocking到死,一定要put进去 |
public E take() throws InterruptedException | blocking 等待获取元素 |
public E poll(long timeout, TimeUnit unit) | blocking 等待获取元素(尝试一段时间) |
public E poll() | blocking到死,一定要 poll 出来 |
public E peek() | 拿到queue的队头 first 的Element |
public boolean remove(Object o) | 先 fullyLock ,然后删掉某个元素 |
public boolean contains(Object o) | 先 fullyLock ,在查看元素是否存在 |
public Object[] toArray() | 先 fullyLock ,再转成数组Array |
public T[] toArray(T[] a) | 先 fullyLock ,再转成数组Array 放到 T[] a 里面去 |
public void clear() | 先 fullyLock,再把内部元素给清空了 |
public int drainTo(Collection<? super E> c, int maxElements) | 先 takeLock,从this中倒出来maxElements 个元素到c里面去。 |
private void writeObject(java.io.ObjectOutputStream s) | 把对象写到输出流,内部重写 |
private void readObject(java.io.ObjectInputStream s) | 把输入流变成对象,内部重写 |
public Iterator iterator() | 得到内部类 Itr |
public Spliterator spliterator() | 得到内部类 new LBQSpliterator(this) |
- 每次 put 都会加上 putLock,满了就会notFull.wait() ,有空间了就 notFull.signal()
- 每次 take 都会加上 takeLock,空了就会 notEmpty.wait(),有货了就 notEmpty.signal()
=== 点击查看top目录 ===
5.3 static 内部类 Node
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
=== 点击查看top目录 ===
5.4 private 内部类 Itr
private class Itr implements Iterator<E> {
private Node<E> current;
private Node<E> lastRet;
private E currentElement;
Itr() {
fullyLock();
try {
current = head.next;
if (current != null)
currentElement = current.item;
} finally {
fullyUnlock();
}
}
public boolean hasNext() {
return current != null;
}
private Node<E> nextNode(Node<E> p) {
for (;;) {
Node<E> s = p.next;
if (s == p)
return head.next;
if (s == null || s.item != null)
return s;
p = s;
}
}
public E next() {
fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
E x = currentElement;
lastRet = current;
current = nextNode(current);
currentElement = (current == null) ? null : current.item;
return x;
} finally {
fullyUnlock();
}
}
public void remove() {
if (lastRet == null)
throw new IllegalStateException();
fullyLock();
try {
Node<E> node = lastRet;
lastRet = null;
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (p == node) {
unlink(p, trail);
break;
}
}
} finally {
fullyUnlock();
}
}
}
- 注意: next() 方法与remove()方法会加fullyLock。
=== 点击查看top目录 ===
5.5 静态内部类LBQSpliterator
static final class LBQSpliterator<E> implements Spliterator<E> {
static final int MAX_BATCH = 1 << 25;
final LinkedBlockingQueue<E> queue;
Node<E> current;
int batch;
boolean exhausted;
long est;
LBQSpliterator(LinkedBlockingQueue<E> queue) {
this.queue = queue;
this.est = queue.size();
}
public long estimateSize() { return est; }
public Spliterator<E> trySplit() {
Node<E> h;
final LinkedBlockingQueue<E> q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((h = current) != null || (h = q.head.next) != null) &&
h.next != null) {
Object[] a = new Object[n];
int i = 0;
Node<E> p = current;
q.fullyLock();
try {
if (p != null || (p = q.head.next) != null) {
do {
if ((a[i] = p.item) != null)
++i;
} while ((p = p.next) != null && i < n);
}
} finally {
q.fullyUnlock();
}
if ((current = p) == null) {
est = 0L;
exhausted = true;
}
else if ((est -= i) < 0L)
est = 0L;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
return null;
}
public void forEachRemaining(Consumer<? super E> action) {
if (action == null) throw new NullPointerException();
final LinkedBlockingQueue<E> q = this.queue;
if (!exhausted) {
exhausted = true;
Node<E> p = current;
do {
E e = null;
q.fullyLock();
try {
if (p == null)
p = q.head.next;
while (p != null) {
e = p.item;
p = p.next;
if (e != null)
break;
}
} finally {
q.fullyUnlock();
}
if (e != null)
action.accept(e);
} while (p != null);
}
}
public boolean tryAdvance(Consumer<? super E> action) {
if (action == null) throw new NullPointerException();
final LinkedBlockingQueue<E> q = this.queue;
if (!exhausted) {
E e = null;
q.fullyLock();
try {
if (current == null)
current = q.head.next;
while (current != null) {
e = current.item;
current = current.next;
if (e != null)
break;
}
} finally {
q.fullyUnlock();
}
if (current == null)
exhausted = true;
if (e != null) {
action.accept(e);
return true;
}
}
return false;
}
public int characteristics() {
return Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT;
}
}
=== 点击查看top目录 ===
5.6 实战 Executors
5.6.1 Executors#newFixedThreadPool
- java.util.concurrent.Executors#newFixedThreadPool(int)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- java.util.concurrent.Executors#newFixedThreadPool(int, java.util.concurrent.ThreadFactory)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
5.6.2 Executors#newSingleThreadExecutor
- java.util.concurrent.Executors#newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- java.util.concurrent.Executors#newSingleThreadExecutor(java.util.concurrent.ThreadFactory)
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
=== 点击查看top目录 ===
六、子类 ArrayBlockingQueue
- 从 tail 插进去,从 head 取出来
- 内部是数组结构
- LinkedBlockingQueue 既继承了 AbstractQueue抽象类又实现了 BlockingQueue,跟 LinkedBlockingQueue 一样
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
6.1 变量
变量 | 备注 |
---|
final Object[] items; | 存储数据的数组 |
int takeIndex; | take 的下标 |
int putIndex; | put 的下标 |
int count; | Queue中的元素数量 |
final ReentrantLock lock; | 锁,存+放共用一个锁 |
private final Condition notEmpty; | 未空Condition,表示可以取 take |
private final Condition notFull; | 未满Condition,表示可以塞 put |
transient Itrs itrs = null; | 遍历用的迭代器 |
=== 点击查看top目录 ===
6.2 方法
方法 | 备注 |
---|
public boolean add(E e) | 内部调用 offer |
public boolean offer(E e) | 先 lock.lock() ,插尾巴,满了就失败,失败直接返回 |
public boolean offer(E e, long timeout, TimeUnit unit) | 先 lock.lock() ,插尾巴,满了就失败,失败循环尝试 N毫秒,依旧不行就返回失败 |
public void put(E e) throws InterruptedException | 先 lock.lock() ,插尾巴,满了就失败,失败就直接无限循环(可以打断) |
public E peek() | 先 lock.lock() ,从头部拉一个元素出来,没元素返回 nul |
public E poll() | 先 lock.lock() ,从头部拉一个元素出来,没元素返回 null |
public E poll(long timeout, TimeUnit unit) throws InterruptedException | 先 lock.lock() ,从头部拉一个元素出来,没元素尝试一段时间,最后还是不行就返回 null |
public E take() throws InterruptedException | 先 lock.lock() ,空了就失败,,失败就直接无限循环(可以打断) |
public int size() | 先 lock.lock() ,再取size |
public int remainingCapacity() | 先 lock.lock() ,再查剩余容量 |
public boolean remove(Object o) | 先 lock.lock() ,然后从头删掉一个 |
public boolean contains(Object o) | 先 lock.lock() ,再去看内部是否contains |
public Object[] toArray() | 先 lock.lock() ,再底层调用 System.arraycopy 进行数组的复制 |
public T[] toArray(T[] a) | 先 lock.lock() ,复制Queue中元素到数组里面去 |
public void clear() | 先 lock.lock() ,把数组内元素设置为 null |
public int drainTo(Collection<? super E> c) | 把this的元素搬运到另一个Collection c |
public int drainTo(Collection<? super E> c, int maxElements) | 把this的元素搬运到另一个Collection c |
public Iterator iterator() | 获取迭代器 Iterator |
private void readObject(java.io.ObjectInputStream s) | 从输入流读取数据 |
没有 writeObject方法 | 因为上面的变量都不是 transient ,也就是不用特殊处理 |
6.3 Demo
private static void test04() throws Exception{
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(2);
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "--- put A");
arrayBlockingQueue.put("A");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
System.out.println("first take ...");
System.out.println(arrayBlockingQueue.take());
System.out.println("end take ...");
}
first take ...
Thread-0--- put A
A
end take ...
- 先 take 阻塞住
- put进去一个元素
- take成功拿到
=== 点击查看top目录 ===
6.4 ArrayBlockingQueue 与 LinkedBlockingQueue区别
- 一个内部是数组(双index),一个内部是链表(单向)
- ArrayBlockingQueue 的读写公用一个 lock,LinkedBlockingQueue 有两个lock,能真正做到同时读写。
- ArrayBlockingQueue 用 int 记录数量,LinkedBlockingQueue 采用 AtomicInteger。
- ArrayBlockingQueue 容量初始化后不能修改,LinkedBlockingQueue 可以一直扩容。
=== 点击查看top目录 ===
七、 子类 SynchronousQueue
- 生产1次,消费1次,再生产,再消费,否则堵塞。
- SynchronousQueue 既继承了 AbstractQueue抽象类又实现了 BlockingQueue,跟 LinkedBlockingQueue 一样
public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
private static final long serialVersionUID = -3223113410248163686L;
- Java 6的SynchronousQueue的实现采用了一种性能更好的无锁算法 — 扩展的“Dual stack and Dual queue”算法。
- 竞争机制支持公平和非公平两种:非公平竞争模式使用的数据结构是后进先出栈(Lifo Stack);公平竞争模式则使用先进先出队列(Fifo Queue),性能上两者是相当的,一般情况下,Fifo通常可以支持更大的吞吐量,但Lifo可以更大程度的保持线程的本地化。
=== 点击查看top目录 ===
7.1 变量
变量 | 备注 |
---|
static final int NCPUS = Runtime.getRuntime().availableProcessors(); | 可用CPU数量 |
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32; | 如果可用cpu是1 ,spin 0次 |
static final int maxUntimedSpins = maxTimedSpins * 16; | |
static final long spinForTimeoutThreshold = 1000L; | spin 上限阈值1000 |
private transient volatile Transferer transferer; | 内部类 Transferer |
private ReentrantLock qlock; | 对象序列化的时候用到 |
private WaitQueue waitingProducers; | 对象序列化的时候用到 |
private WaitQueue waitingConsumers; | 对象序列化的时候用到 |
=== 点击查看top目录 ===
7.2 方法
方法 | 备注 |
---|
public void put(E e) throws InterruptedException | 不会 timeout ,一直阻塞尝试塞入 |
public boolean offer(E e, long timeout, TimeUnit unit) | 会 timeout,尝试塞入 ,失败返回 false |
public boolean offer(E e) | 会 timeout,尝试塞入 ,一次失败返回 false |
public E take() throws InterruptedException | 不会 timeout ,一直阻塞 |
public E poll(long timeout, TimeUnit unit) throws InterruptedException | 会 timeout ,取不到就返回false |
public E poll() | 会 timeout ,一次取不到就返回false |
=== 点击查看top目录 ===
- 特殊处理方法(由于Queue内最多已有一个Element)
方法 | 备注 |
---|
public boolean isEmpty() | return true; |
public int size() | return 0; |
public int remainingCapacity() | return 0; |
public void clear() | {} |
public boolean contains(Object o) | return false; |
public boolean remove(Object o) | return false; |
public boolean containsAll(Collection<?> c) | return c.isEmpty(); c是empty就返回true,其余都是false |
public boolean removeAll(Collection<?> c) | return false; |
public boolean retainAll(Collection<?> c) | return false; |
public E peek() | return null; 窥探一下都不给 |
public Iterator iterator() | return Collections.emptyIterator(); |
public Spliterator spliterator() | return Spliterators.emptySpliterator(); |
public Object[] toArray() | return new Object[0]; |
public T[] toArray(T[] a) | if (a.length > 0) a[0] = null; return a; |
public int drainTo(Collection<? super E> c) | 倒水,poll 最多一个 |
public int drainTo(Collection<? super E> c, int maxElements) | 倒水,poll 最多一个 |
private void writeObject(java.io.ObjectOutputStream s) | |
private void readObject(java.io.ObjectInputStream s) | |
=== 点击查看top目录 ===
7.3 Demo
public static void main(String[] args) throws Exception{
SynchronousQueue<Integer> sc = new SynchronousQueue<>();
new Thread(() ->{
while (true){
try {
int temp = new Random().nextInt(50);
Thread.sleep(500);
System.out.println("put : " + temp + ", 操作运行完毕..." );
sc.offer(temp,5,TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
new Thread(() ->{
while (true){
try {
System.out.println("----------------> sc.take: " + sc.take() + ",获取操作运行完毕..");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
----------------> sc.take: 20,获取操作运行完毕..
put : 20, 操作运行完毕...
----------------> sc.take: 32,获取操作运行完毕..
put : 32, 操作运行完毕...
----------------> sc.take: 48,获取操作运行完毕..
put : 48, 操作运行完毕...
----------------> sc.take: 44,获取操作运行完毕..
put : 44, 操作运行完毕...
put : 18, 操作运行完毕...
----------------> sc.take: 18,获取操作运行完毕..
----------------> sc.take: 12,获取操作运行完毕..
put : 12, 操作运行完毕...
- 生产一个消费一个
- queue必须空才能put成功,queue必须满才能take成功
=== 点击查看top目录 ===
7.4 实战 Executors
7.4.1 Executors#newCachedThreadPool
- 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 (线程可复用)
- 内部使用 SynchronousQueue,也就是生产一个Runnable,消费一个Runnable,这个后续讲解
- java.util.concurrent.Executors#newCachedThreadPool()
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
- java.util.concurrent.Executors#newCachedThreadPool(java.util.concurrent.ThreadFactory)
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
=== 点击查看top目录 ===
八、 子类 PriorityBlockingQueue
- 底层是数组
- 优先级队列,优先级高的,先被 take 出来
- 实现Comparable接口,put的时候进行排序
- 比较规则:当前对象和其他对象做比较,当前优先级大就返回-1,优先级小就返回1
- 优先级队列不允许null值,不允许未实现Comparable接口的对象。
8.1 demo01(不允许未实现Comparable接口的对象)
public static void main(String[] args) throws InterruptedException {
PriorityBlockingQueue<A> queue2 = new PriorityBlockingQueue<>();
queue2.put(new A());
}
private static class A{}
Exception in thread "main" java.lang.ClassCastException: indi.sword.util.concurrent._21_03_TestBlockingQueue_PriorityBlockingQueue$A cannot be cast to java.lang.Comparable
at java.util.concurrent.PriorityBlockingQueue.siftUpComparable(PriorityBlockingQueue.java:358)
at java.util.concurrent.PriorityBlockingQueue.offer(PriorityBlockingQueue.java:490)
at java.util.concurrent.PriorityBlockingQueue.put(PriorityBlockingQueue.java:512)
at indi.sword.util.concurrent._21_03_TestBlockingQueue_PriorityBlockingQueue.main(_21_03_TestBlockingQueue_PriorityBlockingQueue.java:28)
- 结论:抛异常,队内元素必须实现Comparable。
=== 点击查看top目录 ===
8.2 demo02
public static void main(String[] args) throws InterruptedException {
PriorityBlockingQueue<PriorityElement> queue = new PriorityBlockingQueue<>();
for (int i = 0; i < 5; i++) {
Random random = new Random();
PriorityElement element = new PriorityElement(random.nextInt(10));
queue.put(element);
}
while (!queue.isEmpty()){
System.out.println(queue.take());
}
}
@Data
@ToString
class PriorityElement implements Comparable<PriorityElement>{
private int priority;
public PriorityElement(int priority){
this.priority = priority;
}
@Override
public int compareTo(PriorityElement o) {
return this.getPriority() >= o.getPriority() ? -1: 1;
}
}
PriorityElement(priority=5)
PriorityElement(priority=4)
PriorityElement(priority=2)
PriorityElement(priority=1)
PriorityElement(priority=0)
=== 点击查看top目录 ===
九、 子类 DelayQueue
- 缓存系统的设计:使用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,就表示有缓存到期了。
- 定时任务调度:使用DelayQueue保存当天要执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,比如Timer就是使用DelayQueue实现的。
DelayQueue阻塞的是其内部元素,DelayQueue中的元素必须实现 java.util.concurrent.Delayed接口
getDelay()方法的返回值就是队列元素被释放前的保持时间,如果返回0或者一个负值,就意味着该元素已经到期需要被释放,此时DelayedQueue会通过其take()方法释放此对象。
从 Delayed 接口定义可以看到,它还继承了Comparable接口,这是因为DelayedQueue中的元素需要进行排序,一般情况,我们都是按元素过期时间的优先级进行排序。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
9.1 Demo
public class _21_01_TestBlockingQueue_DelayQueue {
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayedElement> queue = new DelayQueue<>();
DelayedElement ele = new DelayedElement("cache 3 seconds",3000);
queue.put(ele);
System.out.println("has put into queue ...");
System.out.println(queue.take());
}
}
@ToString
class DelayedElement implements Delayed{
private long expired;
private long delay;
private String name;
public DelayedElement(String elementName,long delay){
this.name = elementName;
this.delay = delay;
expired = (delay + System.currentTimeMillis());
}
@Override
public int compareTo(Delayed o) {
DelayedElement cached = (DelayedElement)o;
return cached.getExpired() > this.getExpired() ? 1: -1;
}
@Override
public long getDelay(TimeUnit unit) {
return ( this.getExpired() - System.currentTimeMillis());
}
public long getExpired() {
return expired;
}
}
has put into queue ...
DelayedElement(expired=1571302866874, delay=3000, name=cache 3 seconds)
=== 点击查看top目录 ===
9.2 Demo2
public class _21_02_TestBlockingQueue_DelayQueue {
static final int STUDENT_SIZE = 30;
public static void main(String[] args) throws InterruptedException {
Random r = new Random();
DelayQueue<Student> students = new DelayQueue<>();
ExecutorService executorService = Executors.newFixedThreadPool(STUDENT_SIZE);
for (int i = 0; i < STUDENT_SIZE; i++) {
students.put(new Student("学生" + (i+1),3000 + r.nextInt(10000)));
}
while(! students.isEmpty()){
executorService.execute(students.take());
}
executorService.shutdown();
}
}
class Student implements Runnable,Delayed{
private String name;
private long costTime;
private long finishedTime;
public Student(String name,long costTime){
this.name = name;
this.costTime = costTime;
finishedTime = costTime + System.currentTimeMillis();
}
@Override
public void run() {
System.out.println(name + "交卷,用时: " + costTime / 1000 + "s");
}
@Override
public long getDelay(TimeUnit unit) {
return (finishedTime - System.currentTimeMillis());
}
@Override
public int compareTo(Delayed o) {
Student other = (Student)o;
return costTime >= other.costTime ? 1: -1;
}
}
学生17交卷,用时: 3s
学生2交卷,用时: 3s
学生3交卷,用时: 3s
学生16交卷,用时: 3s
学生30交卷,用时: 3s
学生22交卷,用时: 5s
学生29交卷,用时: 5s
学生25交卷,用时: 5s
学生18交卷,用时: 6s
学生28交卷,用时: 6s
学生14交卷,用时: 6s
学生23交卷,用时: 6s
学生19交卷,用时: 7s
学生11交卷,用时: 7s
学生9交卷,用时: 7s
学生27交卷,用时: 7s
学生7交卷,用时: 7s
学生15交卷,用时: 7s
学生26交卷,用时: 7s
学生8交卷,用时: 8s
学生4交卷,用时: 9s
学生1交卷,用时: 9s
学生24交卷,用时: 10s
学生20交卷,用时: 10s
学生6交卷,用时: 10s
学生10交卷,用时: 11s
学生21交卷,用时: 11s
学生12交卷,用时: 12s
学生13交卷,用时: 12s
学生5交卷,用时: 12s
=== 点击查看top目录 ===
十、番外篇
下一章节::【Java Collection】子类 SynchronousQueue 图解剖析(五)
上一章节:【Java Collection】常见 List 子类剖析(三)