在之前的文章中曾经为大家介绍了java并发编程的工具:BlockingQueue接口、ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue,本文为系列文章第六篇。

本篇文章将为大家介绍并发编程汇合类SynchronousQueue,它是BlockingQueue接口的实现类。与所有的BlockingQueue接口实现类不同的是:SynchronousQueue队列的容量永远是0(或者能够了解为容量为1的队列,然而说队列容量为1并不精确),这是因为SynchronousQueue实际上它不是一个真正的队列,因为它不会为队列中元素保护存储空间,它只是多个线程之间数据交换的媒介。

  • SynchronousQueue队列的一个线程的插入动作总是会期待另一个线程的移除操作,反之亦然。
  • put()办法放入元素对象到 SynchronousQueue不会返回后果(处于阻塞状态),直到另一个线程执行take()移除元素对象.
  • peek()办法在BlockingQueue接口实现类中能够获取元素,但不从队列中移除该元素。但在SynchronousQueue队列中该办法不可用。

SynchronousQueue 同步队列例子

上面咱们写一个例子,来帮忙咱们了解SynchronousQueue的个性及用法。
SynchronousQueueProducer.java 启动线程每隔一秒向队列中放入一个Integer对象。

public class SynchronousQueueProducer implements Runnable {   protected BlockingQueue<Integer> blockingQueue;   public SynchronousQueueProducer(BlockingQueue<Integer> queue) {      this.blockingQueue = queue;   }   @Override   public void run() {      int i = 0;      while (true) {         System.out.println(Thread.currentThread().getName() + " Put: " + ++i);         try {            blockingQueue.put(i);            Thread.sleep(1000);  //每隔一秒生产一次         } catch (InterruptedException e) {            e.printStackTrace();         }      }   }}

SynchronousQueueConsumer.java启动线程每5秒从队列中取出一个元素对象。

public class SynchronousQueueConsumer implements Runnable {   protected BlockingQueue<Integer> blockingQueue;   public SynchronousQueueConsumer(BlockingQueue<Integer> queue) {      this.blockingQueue = queue;   }   @Override   public void run() {      while (true) {         try {            Integer data = blockingQueue.take();            System.out.println(Thread.currentThread().getName() + " take(): " + data);            Thread.sleep(5000);  //每隔5秒生产一次         } catch (InterruptedException e) {            e.printStackTrace();         }      }   }}

SynchronousQueueExample.java 新建一个SynchronousQueue同步队列,启动一个生产者线程插入对象,两个消费者线程移除对象。进行测试,看看成果。

public class SynchronousQueueExample {    public static void main(String[] args) {      final BlockingQueue<Integer> synchronousQueue = new SynchronousQueue<>();          SynchronousQueueProducer queueProducer = new SynchronousQueueProducer(synchronousQueue);      new Thread(queueProducer).start();          SynchronousQueueConsumer queueConsumer1 = new SynchronousQueueConsumer(synchronousQueue);      new Thread(queueConsumer1).start();          SynchronousQueueConsumer queueConsumer2 = new SynchronousQueueConsumer(synchronousQueue);      new Thread(queueConsumer2).start();    }}

剖析一下试验的后果,Thread-0 是生产者线程,Thread-1 和 Thread-2是消费者线程。从试验后果咱们能够看到SynchronousQueue必须是生产一次、生产一次、生产一次、生产一次,不管有多少个消费者和生产者线程都必须遵循这个规定。

Thread-0 Put: 1Thread-1 take(): 1Thread-0 Put: 2Thread-2 take(): 2Thread-0 Put: 3Thread-1 take(): 3Thread-0 Put: 4Thread-2 take(): 4Thread-0 Put: 5Thread-1 take(): 5Thread-0 Put: 6Thread-2 take(): 6Thread-0 Put: 7Thread-1 take(): 7Thread-0 Put: 8Thread-2 take(): 8Thread-0 Put: 9Thread-1 take(): 9Thread-0 Put: 10Thread-2 take(): 10Thread-0 Put: 11Thread-1 take(): 11Thread-0 Put: 12Thread-2 take(): 12

利用场景:如果咱们不确定来自生产者申请数量,然而这些申请须要很快的解决掉,那么配合SynchronousQueue为每个生产者申请调配一个生产线程是最解决效率最高的方法。Executors.newCachedThreadPool()底层就应用了SynchronousQueue,这个线程池依据需要创立新的线程。

欢送关注我的博客,外面有很多精品合集

本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 - zimug.com

感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源! 。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。

  • 《手摸手教你学Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《实战前后端拆散RBAC权限管理系统》
  • 《实战SpringCloud微服务从青铜到王者》
  • 《VUE深入浅出系列》