多线程(60)SynchronousQueue和它的用途

SynchronousQueue是一个没有存储空间的阻塞队列,它是java.util.concurrent包中的一部分。每一个put操作必须等待一个take操作,反之亦然。SynchronousQueue内部并不维护任何元素的存储,可以认为它是一种线程之间一对一传递消息的机制。

核心特性

  • 不存储元素SynchronousQueue不是用来存储元素的,每个插入操作必须等待另一个线程的移除操作。
  • 公平性选择 :构造SynchronousQueue时可以选择公平策略,如果设置为公平模式,队列会按照线程等待的顺序来处理线程的插入和移除请求。

用途

SynchronousQueue通常用于传递性场景和线程池的工作队列。例如,在ThreadPoolExecutor中,如果创建了一个基于SynchronousQueue的线程池,提交任务时若有空闲线程则立即执行,若没有空闲线程则尝试创建新线程执行,如果线程数已达最大,则执行拒绝策略。

源码解析(简化)

SynchronousQueue的实现涉及到复杂的并发控制。以下是它的简化源码逻辑:

java 复制代码
public class SynchronousQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {

    // 省略了锁和条件变量的实现细节
    
    public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        // 将元素提供给正在等待的消费者
        if (!transferer.transfer(e, true, 0L)) {
            // 如果没有正在等待的消费者,则阻塞生产者线程直到元素被消费
            // 中断策略等逻辑在实际源码中有详细的实现,这里简化
            // transferer.transfer 实现了元素的传递逻辑
        }
    }

    public E take() throws InterruptedException {
        E e = transferer.transfer(null, false, 0L);
        if (e != null)
            return e;
        // 如果没有可用的元素,则阻塞消费者线程直到生产者线程插入元素
        // 中断策略等逻辑在实际源码中有详细的实现,这里简化
    }

    // 其他方法...
}

代码演示

这是一个SynchronousQueue的简单使用示例:

java 复制代码
import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueDemo {

    public static void main(String[] args) {
        SynchronousQueue<String> queue = new SynchronousQueue<>();

        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                String event = queue.take();
                System.out.println("消费了一个事件: " + event);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 生产者线程
        Thread producer = new Thread(() -> {
            try {
                String event = "四月之声";
                queue.put(event);
                System.out.println("生产了一个事件: " + event);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        consumer.start();
        producer.start();
    }
}

注意事项

  • 阻塞行为SynchronousQueue的操作几乎在所有情况下都可能阻塞,因为它不存储元素。
  • 中断 :等待的线程可以响应中断,当线程在puttake时阻塞,如果线程被中断,将抛出InterruptedException
  • 元素空间 :因为队列内部没有存储空间,所以peekcontainsclearisEmpty等方法不是很有意义,这些方法的实现总是返回特定的值(例如isEmpty总是返回true)。

SynchronousQueue是一个非常低层次的同步机制,它为高并发场景提供了一种线程间单个元素的交换方式。在设计高并发系统时,SynchronousQueue可以作为构建更高级同步结构的基础组件。

相关推荐
yuhaiqiang7 分钟前
【珍藏干货】累计阅读破百万:我如何靠“标题公式”把冷门技术写出爆款的?
前端·后端·程序员
艾莉丝努力练剑11 分钟前
【Linux系统:多线程】线程概念与控制
linux·运维·服务器·c++·后端·学习·操作系统
喝醉的小喵15 分钟前
iptables 规则重启机器后丢失导致k8s网络不可用
网络·后端·容器·kubernetes·虚拟化
人间打气筒(Ada)16 分钟前
「码动四季·开源同行」go语言:如何处理 Go 错误异常与并发陷阱?
开发语言·后端·golang·defer·panic·errors·并发陷阱
女王大人万岁20 分钟前
Golang实战gin-swagger:自动生成API文档
服务器·开发语言·后端·golang·gin
小林学编程36 分钟前
模型上下文协议(MCP)的理解
java·后端·llm·prompt·resource·tool·mcp协议
小码哥_常10 小时前
Spring Boot 中JWT登录授权+无感刷新,看这篇就够了!
后端
码农BookSea11 小时前
深度解析Skills:从Prompt到能力复用的技术革命
后端·ai编程
计算机毕设指导611 小时前
基于SpringBoot校园学生健康监测管理系统【源码文末联系】
java·spring boot·后端·spring·tomcat·maven·intellij-idea
希望永不加班11 小时前
SpringBoot 数据库连接池配置(HikariCP)最佳实践
java·数据库·spring boot·后端·spring