关于spring:java并发编程工具类JUC第六篇SynchronousQueue同步队列

5次阅读

共计 2942 个字符,预计需要花费 8 分钟才能阅读完成。


在之前的文章中曾经为大家介绍了 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: 1
Thread-1 take(): 1
Thread-0 Put: 2
Thread-2 take(): 2
Thread-0 Put: 3
Thread-1 take(): 3
Thread-0 Put: 4
Thread-2 take(): 4
Thread-0 Put: 5
Thread-1 take(): 5
Thread-0 Put: 6
Thread-2 take(): 6
Thread-0 Put: 7
Thread-1 take(): 7
Thread-0 Put: 8
Thread-2 take(): 8
Thread-0 Put: 9
Thread-1 take(): 9
Thread-0 Put: 10
Thread-2 take(): 10
Thread-0 Put: 11
Thread-1 take(): 11
Thread-0 Put: 12
Thread-2 take(): 12

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

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

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

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

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