文章目录
1 介绍
SynchronousQueue也是实现自BlockingQueue的一个阻塞队列,每一次对其的写入操作必须等待(阻塞)其他线程进行对应的移除操作,SynchronousQueue的内部并不会涉及容量、获取size,就连peek方法的返回值永远都将会是null,除此之外还有更多的方法在SynchronousQueue中也都未提供对应的支持(列举如下),因此在使用的过程中需要引起注意,否则会使得程序的运行出现不符合预期的错误。
- clear():清空队列的方法在SynchronousQueue中不起任何作用。
- contains(Object o):永远返回false。
- containsAll(Collection<?> c):等价于c是否为空的判断。
- isEmpty():永远返回true。
- iterator():返回一个空的迭代器。
- peek():永远返回null。
- remainingCapacity():始终返回0。
- remove(Object o):不做任何删除,并且始终返回false。
- removeAll(Collection<?> c):不做任何删除,始终返回false。
- retainAll(Collection<?> c):始终返回false。
- size():返回值始终为0。
- spliterator():返回一个空的Spliterator
- toArray()及toArray(T[] a)方法同样也不支持。
看起来好多方法在SynchronousQueue中都不提供对应的支持,那么SynchronousQueue是一个怎样的队列呢?简单来说,我们可以借助于SynchronousQueue在两个线程间进行线程安全的数据交换
主要作用在于在两个线程之间进行数据交换,区别于Exchanger的主要地方在于(站在使用的角度)SynchronousQueue所涉及的一对线程一个更加专注于数据的生产,另一个更加专注于数据的消费(各司其职),而Exchanger则更加强调一对线程数据的交换。
SynchronousQueue在日常的开发使用中并不是很常见,即使在JDK内部,该队列也仅用于ExecutorService中的Cache Thread Pool创建
2 代码示例:数据交换
public class SynchronousQueueTest {
public static void main(String[] args) {
// 定义String类型的SynchronousQueue
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 定义两个线程,写入数据
IntStream.rangeClosed(0, 1).forEach(i->{
new Thread(()->{
try {
// 若没有对应的数据消费线程,则put方法将会导致当前线程进入阻塞
queue.put(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName() + " put data -> " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"P-" +i).start();
});
// 启动两个线程从queue中消费数据
IntStream.rangeClosed(0, 1).forEach(i->{
new Thread(()->{
try {
// 若没有对应的数据生产线程,则take方法将会导致当前线程进入阻塞
String data = queue.take();
System.out.println(Thread.currentThread().getName() + " take data -> " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"C-" +i).start();
});
}
}
C-0 take data -> P-1
C-1 take data -> P-0
P-0 put data -> P-0
P-1 put data -> P-1