从零开始实现lmax-Disruptor队列(六)Disruptor 解决伪共享、消费者优雅停 ...

打印 上一主题 下一主题

主题 883|帖子 883|积分 2649

MyDisruptor V6版本介绍

在v5版本的MyDisruptor实现DSL风格的API后。按照计划,v6版本的MyDisruptor作为最后一个版本,需要对MyDisruptor进行最终的一些细节优化。
v6版本一共做了三处优化:

  • 解决伪共享问题
  • 支持消费者线程优雅停止
  • 生产者序列器中维护消费者序列集合的数据结构由ArrayList优化为数组Array类型(减少ArrayList在get操作时额外的rangeCheck检查)


由于该文属于系列博客的一部分,需要先对之前的博客内容有所了解才能更好地理解本篇博客
伪共享问题(FalseSharing)原理详解

在第一篇博客中我们就已经介绍过伪共享问题了,这里复制原博客内容如下:
现代的CPU都是多核的,每个核心都拥有独立的高速缓存。高速缓存由固定大小的缓存行组成(通常为32个字节或64个字节)。CPU以缓存行作为最小单位读写,且一个缓存行通常会被多个变量占据(例如32位的引用指针占4字节,64位的引用指针占8个字节)。
这样的设计导致了一个问题:即使缓存行上的变量是无关联的(比如不属于同一个对象),但只要缓存行上的某一个共享变量发生了变化,则整个缓存行都会进行缓存一致性的同步。
而CPU间缓存一致性的同步是有一定性能损耗的,能避免则尽量避免。这就是所谓的“伪共享”问题。
disruptor通过对队列中一些关键变量进行了缓存行的填充,避免其因为不相干的变量读写而无谓的刷新缓存,解决了伪共享的问题。
举例展示伪共享问题对性能的影响


  • 假设存在一个Point对象,其中有两个volatile修饰的long类型字段,x和y。
    有两个线程并发的访问一个Point对象,但其中一个线程1只读写x字段,而另一个线程2只读写y字段。
存在伪共享问题的demo
  1. public class Point {
  2.     public volatile int x;
  3.     public volatile int y;
  4.     public Point(int x, int y) {
  5.         this.x = x;
  6.         this.y = y;
  7.     }
  8. }
复制代码
[code]import java.util.concurrent.CountDownLatch;import java.util.concurrent.SynchronousQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class FalseSharingDemo {    public static void main(String[] args) throws InterruptedException {        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 60L, TimeUnit.SECONDS, new SynchronousQueue());        CountDownLatch countDownLatch = new CountDownLatch(2);        Point point = new Point(1,2);        long start = System.currentTimeMillis();        executor.execute(()->{            // 线程1 x自增1亿次            for(int i=0; i{            // 线程2 y自增1亿次            for(int i=0; i{            // 线程1 x自增1亿次            for(int i=0; i{            // 线程2 y自增1亿次            for(int i=0; i
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

飞不高

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表