线程安全的不存储元素的阻塞队列SynchronousQueue

SynchronousQueue是一个不存储元素的阻塞队列,每一个 put 操作必须等待 take 操作,否则不能继续添加元素。支持公平锁和非公平锁2种策略来访问队列。默认是采用非公平性策略访问队列。公平性策略底层使用了类似队列的数据结构,而非公平策略底层使用了类似栈的数据结构。SynchronousQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue

队列创建

SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>();

应用场景

SynchronousQueue可以看成是一个传球手,负责把生产者线程处理的数据直接传递给消费者线程。队列本身并不存储任何元素,非常适合传递性场景

SynchronousQueue 的一个使用场景是在线程池里。Executors.newCachedThreadPool() 就使用了 SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。

我们来看一个具体的例子:

public class TestSynchronousQueue {

    public static void main(String[] args) {
        SynchronousQueue<Integer> queue = new SynchronousQueue<>();
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);
        Thread t1 = new Thread(consumer);
        Thread t2 = new Thread(producer);
        t1.start();
        t2.start();
    }

}

/**
 * 模拟生产者
 */
class Producer implements Runnable {

    SynchronousQueue<Integer> queue = null;


    public Producer(SynchronousQueue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        int rand = new Random().nextInt(1000);
        System.out.println(String.format("模拟生产者:%d", rand));

        try {
            TimeUnit.SECONDS.sleep(3);
            queue.put(rand);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(queue.isEmpty());
    }
}

/**
 * 模拟消费者
 */
class Consumer implements Runnable {

    SynchronousQueue<Integer> queue = null;

    public Consumer(SynchronousQueue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("消费者已经准备好接收元素了...");
        try {
            System.out.println(String.format("消费一个元素:%d", queue.take()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("================================================");
    }
}

工作原理

由于SynchronousQueue的支持公平策略和非公平策略,所以底层有两种数据结构

  • 队列(实现公平策略),有一个头结点和尾结点,并配合一个FIFO队列来阻塞多余的生产者和消费者,从而体系整体的公平策略;
  • 栈(实现非公平策略),有一个头结点(为默认策略),同时配合一个LIFO队列来管理多余的生产者和消费者,而后一种模式,如果生产者和消费者的处理速度有差距,则很容易出现饥渴的情况,即可能有某些生产者或者是消费者的数据永远都得不到处理。

队列与栈都是通过链表来实现的。具体的数据结构如下:

nc9zv21jd3.png

 

参考文章:

 

posted @ 2022-02-08 18:07  残城碎梦  阅读(125)  评论(0编辑  收藏  举报