共计 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 深入浅出系列》