1 概述
- java.util.concurrent.SynchronousQueue
- SynchronousQueue 是一种阻塞队列,其实现了 BlockingQueue 接口。
- 容量为 0,该队列仅用于数据的交换,比如有两个线程,一个新增数据,另一个必须删除数据,否则就会阻塞新增或者删除的线程。
- 非常适合切换设计,在该设计中,一个线程中运行的对象必须与在另一个线程中运行的对象同步,以便向其传递一些信息,事件或任务。
- 尽管 SynchronousQueue 也实现了 Queue 接口,但是真正有用的就只有 take 和 put 这两个方法,并且都会阻塞调用这两个方法的线程。
- 功能上和 TransferQueue 以及 Exchanger 非常类似。
- 线程池工具类 Executors 的 newCachedThreadPool 就是用 SynchronousQueue 作为任务队列的。
2 关键点
- 用于两个线程间以同步的方式来交换一些信息,事件或任务
- 内部通过 TransferQueue 来实现
- 容量为 0,调用其中的 size 和 remainingCapacity 方法都返回为 0,isEmpty 方法永远返回 true.
3 举例说明
比如去食堂打饭的时候,你把空餐盘递给阿姨后,阿姨在餐盘上放上饭菜,然后再递给你。
这里把打饭窗口比作 SynchronousQueue 队列,食客先将餐盘放到队列中,阿姨才能取出餐盘,阿姨打饭后将餐盘放到队列,食客才能取出。
3.1 餐盘对象 Plate
1 | /** |
3.2 食客线程对象 EaterWorker
- 食客线程先将餐盘交给阿姨,在队列上 put
- 阿姨打饭完毕后,食客从队列中 take 出食物
1 | import org.slf4j.Logger; |
3.3 打饭阿姨线程对象 AuntWorker
- 阿姨线程先从队列中拿到食客的餐盘 take
- 在餐盘上放置食物后,在把餐盘 put 到队列中
1 | import com.ckjava.synchronizeds.appCache.WaitUtils; |
3.4 测试
在线程池中启动了两个线程,一个是阿姨线程,一个是吃客线程
1 | import com.ckjava.synchronizeds.appCache.WaitUtils; |
- 输出如下
1 | 11:33:08.510 [pool-1-thread-1] INFO c.c.SynchronizedQueue.EaterWorker - 食客在窗口上放上餐盘,等待阿姨打饭 |