美文网首页
JCTools中的queue

JCTools中的queue

作者: rock_fish | 来源:发表于2020-01-03 17:29 被阅读0次

所属文集:一起掌握并发

Netty后来版本中使用了JCTools中的queue;

JDK自带的queue和JCTools的queue对比效果

100万数据
括号中的213是秒数。比如4901/s (213) 用时213秒,平均每秒钟处理4901条。
capacity 其值的大小对结果的影响是蛮大的

Producer Consumer capacity LinkedBlockingQueue ArrayBlockingQueue MpscLinkedAtomicQueue MpscChunkedArrayQueue MpscArrayQueue
128 1 128 4901/s (213) 38518/s (27) 17702070/s (0) 153652/s (6) 161788/s (6)
128 1 256 10210/s (102) 64686/s (16) 21769821/s (0) 154687/s (6) 181169/s (5)
128 1 512 26195/s (40) 99332/s (10) 20426455/s (0) 184272/s (5) 193574/s (5)
128 1 1024 160711/s (6) 146096/s (7) 22314536/s (0) 108893/s (9) 213303/s (4)
256 1 128 2518/s (416) 18079/s (57) 4699428/s (0) 55165/s (19) 91258/s (11)
256 1 256 5418/s (193) 27639/s (37) 20966414/s (0) 56481/s (18) 74522/s (14)
256 1 512 17290/s (60) 41326/s (25) 21005054/s (0) 68642/s (15) 111464/s (9)
256 1 1024 27646/s (37) 81722/s (12) 20153991/s (0) 52241/s (20) 84719/s (12)

MPSC的高性能操作总结。
  • Single Writer Principle(单写原则)
    MP是多写,没有这个原则。

  • lazy set

  1. lazySet是使用Unsafe.putOrderedObject方法,会前置一个store-store barrier(在当前的硬件体系下或者是no-op或者非常轻),而不是store-load barrier, store-load barrier较慢,总是用在volatile的写操作上。在操作序列Store1; StoreStore;Store2中,Store1的数据会在Store2和后续写操作之前对其它处理器可见。换句话说,就是保证了对其它数据可见的写的顺序。
    如果只有一个线程写我们就用不着store-load barrier,lazySet和volatile set在单写原则下面是等价的。 这种性能提升是有代价的,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,lazySet的写在实践上来延迟是纳秒级,这个时间比较短,所以代价可以忍受。 类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右,store-store的劣势是纳秒级的延迟。

总结:在MPSC的场景下,写的时候只需通过 StoreStore 保证写的顺序不乱,因为当前线程只负责写进去就行了,不需要读取(可见)这个最新值,
其他线程在需要读取的时候,在读取的操作中 加入load barrier 来保证;

  • 向buffer中写数据 StoreStore,保证写入顺序
    /**
     * An ordered store(store + StoreStore barrier) of an element to a given offset
     */
    public static <E> void soElement(E[] buffer, long offset, E e)
    {
        UNSAFE.putOrderedObject(buffer, offset, e);
    }
  • 从buffer中读数据 LoadLoad,保证读取最新数据。
    /**
     * A volatile load (load + LoadLoad barrier) of an element from a given offset.
     */
    @SuppressWarnings("unchecked")
    public static <E> E lvElement(E[] buffer, long offset)
    {
        return (E) UNSAFE.getObjectVolatile(buffer, offset);
    }

扩展知识点:unsafe中提供的读写操作:

//A volatile load (load + LoadLoad barrier) of an element from a given offset.
//从对象的指定偏移量处获取变量的引用,使用volatile的加载语义
public native Object getObjectVolatile(Object o, long offset);

//存储变量的引用到对象的指定的偏移量处,使用volatile的存储语义
public native void putObjectVolatile(Object o, long offset, Object x);
//有序、延迟版本的putObjectVolatile方法,不保证值的改变被其他线程立即看到。只有在field被volatile修饰符修饰时有效
//An ordered store(store + StoreStore barrier) of an element to a given offset
public native void putOrderedObject(Object o, long offset, Object x);

-----------------
//A plain store (no ordering/fences) of an element to a given offset
//获得给定对象的指定地址偏移量的值,与此类似操作还有:getInt,getDouble,getLong,getChar等
public native Object getObject(Object o, long offset);
//给定对象的指定地址偏移量设值,与此类似操作还有:putInt,putDouble,putLong,putChar等
public native void putObject(Object o, long offset, Object x);
  • 大量的位运算
    在前面中也看到了,通过&运算得到数组的下标,<< 计算数组的偏移地址,再利用unsafe进行设置等操作。举个例子%运算耗时是&的两倍。
public static long calcElementOffset(long index, long mask)
    {
        return REF_ARRAY_BASE + ((index & mask) << REF_ELEMENT_SHIFT);
    }
//index & mask 等同于 % 取余 ;取4的余数,mask =(4-1) 
//REF_ELEMENT_SHIFT = 2 ;
//<< REF_ELEMENT_SHIFT : 左移2 等同于 * 4
感谢你们:

高性能SPSC无锁队列设计之路
Netty中Queue的实现
新版Netty中,使用JCTools中的容器
Netty解读:Jctools高性能无锁队列源码分析
AtomicLong.lazySet是如何工作的?
Java中的指针:Unsafe类

思考Java中的指针:Unsafe类中的这段话:
在Java中使用本地内存有它的意义。从延迟的角度来说,直接访问本地内存不会比访问Java堆快。这个结论其实是有道理的,因为跨越JVM屏障肯定是有开销的。这样的结论对使用本地还是堆的ByteBuffer同样适用。使用本地ByteBuffer的速度提升不在于访问这些内存,而是它可以直接与操作系统提供的本地IO进行操作。

Java并发编程系列:漫谈伪共享
Java并发编程系列:CAS 详解
JVM系列:二、虚拟机中的对象布局

相关文章

  • JCTools中的queue

    所属文集:一起掌握并发 Netty后来版本中使用了JCTools中的queue; JDK自带的queue和JCTo...

  • Jctools Queue队列

    JCTools是一款对jdk并发数据结构进行增强的并发工具,主要提供了非阻塞Map以及无锁Queue的增强数据结构...

  • 2020-05-17-Java数据结构-Stack和Queue

    Stack Queue 参考: java 中的Stack、Queue、Deque

  • GCD温故而知新1

    GCD 三中queue1.1 main queue1.2 global queue1.3 自己创建 queue1....

  • C++面向对象程序设计-Third Week

    Knowledge Point: Composition(复合): queue类中引入deque类,queue类中...

  • 多线程爬虫

    多线程爬虫 Queue(队列对象) Queue是python中的标准库,可以直接import Queue引用; 队...

  • Python实现的EventLoop

    EventLoop 测试 关键 Event: Event Queue Loop: 循环处理Queue中的Event...

  • Python队列-Queue

    Queue 说明 初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或...

  • GCD

    Dispatch Queue的种类 Serial Dispatch Queue 等待现在执行中处理结束 (按照追加...

  • C++ - STL中的queue

    queue queue模板类的定义在 头文件中。queue是容器适配器的一种,用于执行FIFO(first-in ...

网友评论

      本文标题:JCTools中的queue

      本文链接:https://www.haomeiwen.com/subject/mjcdoctx.html