Java多线程进阶(37)—— J.U.C之collections框架:LinkedTransferQueue

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

一、LinkedTransferQueue简介

LinkedTransferQueue是在JDK1.7时,J.U.C包新增的一种比较特殊的阻塞队列,它除了具备阻塞队列的常用功能外,还有一个比较特殊的transfer方法。

我们知道,在普通阻塞队列中,当队列为空时,消费者线程(调用 take 或 poll 方法的线程)一般会阻塞等待生产者线程往队列中存入元素。而 LinkedTransferQueue 的 transfer 方法则比较特殊:

  1. 当有消费者线程阻塞等待时,调用transfer方法的生产者线程不会将元素存入队列,而是直接将元素传递给消费者;
  2. 如果调用transfer方法的生产者线程发现没有正在等待的消费者线程,则会将元素入队,然后会阻塞等待,直到有一个消费者线程来获取该元素。

TransferQueue接口

可以看到,LinkedTransferQueue实现了一个名为TransferQueue的接口,TransferQueue也是JDK1.7时J.U.C包新增的接口,正是该接口提供了上述的transfer方法:

除了transfer方法外,TransferQueue还提供了两个变种方法:tryTransfer(E e)tryTransfer(E e, long timeout, TimeUnit unit)

tryTransfer(E e)
当生产者线程调用tryTransfer方法时,如果没有消费者等待接收元素,则会立即返回false。该方法和transfer方法的区别就是tryTransfer方法无论消费者是否接收,方法立即返回,而transfer方法必须等到消费者消费后才返回。

tryTransfer(E e, long timeout, TimeUnit unit)
tryTransfer(E e,long timeout,TimeUnit unit)方法则是加上了限时等待功能,如果没有消费者消费该元素,则等待指定的时间再返回;如果超时还没消费元素,则返回false,如果在超时时间内消费了元素,则返回true。

TransferQueue接口定义:

LinkedTransferQueue的特点简要概括如下:

  1. LinkedTransferQueue是一种无界阻塞队列,底层基于单链表实现;
  2. LinkedTransferQueue中的结点有两种类型:数据结点、请求结点;
  3. LinkedTransferQueue基于无锁算法实现。

二、LinkedTransferQueue原理

2.1 内部结构

LinkedTransferQueue提供了两种构造器,也没有参数设置队列初始容量,所以是一种 无界队列 :

    /**
     * 队列结点定义.
     */
    static final class Node {
        final boolean isData;   // true: 数据结点; false: 请求结点
        volatile Object item;   // 结点值
        volatile Node next;     // 后驱结点指针
        volatile Thread waiter; // 等待线程
    
        // 设置当前结点的后驱结点为val
        final boolean casNext(Node cmp, Node val) {
            return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
        }
    
        // 设置当前结点的值为val
        final boolean casItem(Object cmp, Object val) {
            // assert cmp == null || cmp.getClass() != Node.class;
            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
        }
    
        Node(Object item, boolean isData) {
            UNSAFE.putObject(this, itemOffset, item); // relaxed write
            this.isData = isData;
        }
    
        // 设置当前结点的后驱结点为自身
        final void forgetNext() {
            UNSAFE.putObject(this, nextOffset, this);
        }
    
        /**
         * 设置当前结点的值为自身.
         * 设置当前结点的等待线程为null.
         */
        final void forgetContents() {
            UNSAFE.putObject(this, itemOffset, this);
            UNSAFE.putObject(this, waiterOffset, null);
        }
    
        /**
         * 判断当前结点是否匹配成功.
         * Node.item == this || (Node.isData == true && Node.item == null)
         */
        final boolean isMatched() {
            Object x = item;
            return (x == this) || ((x == null) == isData);
        }
    
        /**
         * 判断是否为未匹配的请求结点.
         * Node.isData == false && Node.item == null
         */
        final boolean isUnmatchedRequest() {
            return !isData && item == null;
        }
    
        /**
         * 当该结点(havaData)是未匹配结点, 且与当前的结点类型不同时, 返回true.
         */
        final boolean cannotPrecede(boolean haveData) {
            boolean d = isData;
            Object x;
            return d != haveData && (x = item) != this && (x != null) == d;
        }
    
        /**
         * 尝试匹配数据结点.
         */
        final boolean tryMatchData() {
            // assert isData;   当前结点必须为数据结点
            Object x = item;
            if (x != null && x != this && casItem(x, null)) {
                LockSupport.unpark(waiter);     // 唤醒等待线程
                return true;
            }
            return false;
        }
    
        // Unsafe mechanics
        private static final sun.misc.Unsafe UNSAFE;
        private static final long itemOffset;
        private static final long nextOffset;
        private static final long waiterOffset;
    
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> k = Node.class;
                itemOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("item"));
                nextOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("next"));
                waiterOffset = UNSA
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值