关于线程间传递数据的队列,SynchronousQueue队列

是一个支持公平和非公平的线程安全的队列

对于在HikariCP中,其对应的实现是选择了对应的公平模式,

this.handoffQueue = new SynchronousQueue<>(true)

内部维护的是一个无存储空间的阻塞队列,生产者和消费者之间的线程可以线程同步的传递某些信息或者时间,也就是说一个读操作需要一个写操作,缺少一个就会阻塞线程,直到匹配位置

基于了队列和栈来实现,双队列提供了公平模式,双栈则是非公平模式

其内部的字段主要有个

1.NCPUS:代表CPU的数量

2.maxTimedSpins:自旋的次数,如果指定了timeout的事件,则使用maxTimeSpins,如果CPU小于2则自旋次数为0,一个常量而已

3.maxUntimedSpins:自选测试,同样一个常量

4.自定义时间:防止自定义时间过长的保护常量罢了

一个生产线程,当它生产产品(即put的时候),如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线程调用take操作,take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传递),这样的一个过程称为一次配对过程(当然也可以先take后put,原理是一样的)

关于其中的公平队列,采用了双队列的模式,进行互补的等待,如果模式相同,就进行等待,互补再进行消费

图片

图片

那么是如何存入和消费的呢?

如果是公平模型下的存入和消费

底层实现使用的是TransferQueue这个内部队列,它有一个head和tail指针,用于指向当前正在等待匹配的线程节点。

初始化时,TransferQueue的状态如下:

图片

接下来入队两个put请求,分别自旋后睡眠

图片

然后来了一个线程进行take,take线程指向put2,但由于是公平策略,于是队头出队

执行后put1线程被唤醒,take1线程的 take()方法返回了1(put1线程的数据),这样就实现了线程间的一对一通信,这时候内部状态如下:

图片

如果是非公平模型,则如下:

使用的是TransferStack

仍然是两个线程进行了put操作,进行自旋的睡眠

图片

然后进行一个take,执行了take操作,就会发现栈顶为put2,然后出栈配对

图片

后进先出的栈在这里体现的淋漓尽致

SynchronousQueue由于内部的线程匹配机制,在大部分的开发中,不会使用,但是线程池中可能会设计,毕竟没有使用AQS,而是CAS,导致不容易理解

发表评论

邮箱地址不会被公开。 必填项已用*标注