0%

并发设计案例

并发设计案例

06并发设计案例

40Disruptor

  • 优化点

    1. 内存分配优化

      1. 采用ringbuffer数据结构

        数组序号长度为二的n次方,真实下标计算时使用二级制与,比模取余更快

      2. 数组中的对像在数组初始化时也全部初始化。提升CPU缓存命中率,防止垃圾回收。消费后不删除,生产时覆盖

      3. 避免伪共享

        伪共享:由于共享缓存行导致缓存无效,只能从内存读取数据的场景。

        共享:不同核可读取CPU缓存,而不用读取内存

        takeIndex 通过填充字节来独占缓存行

    2. 无锁生产、消费

  • 缺点

    • 使用复杂
    • 占用内存高

41 高性能数据库连接池HiKariCP

数据库连接池:c3p0、DBCP、Tomcat JDBC Connection Pool、Druid、HiKariCP

池化资源作用:避免重量级资源的频繁创建和销毁

HiKariCP性能高的原因:

  • 微观:从字节码的角度优化Java代码

  • 宏观:两个数据结构

    • FastList

      将一个Connection创建的多个Statement 保存在数组 Fast中

      1. 删除时从后往前遍历。添加Statement是S1,S2,关闭时一般是S2,S1
      2. get(int index) 没有做越界检查。todo
    • ConcurrentBag

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      // 用于存储所有的数据库连接
      CopyOnWriteArrayList<T> sharedList;
      // 线程本地存储中的数据库连接
      ThreadLocal<List<Object>> threadList;
      // 等待数据库连接的线程数
      AtomicInteger waiters;
      // 分配数据库连接的工具,线程之间传递数据
      SynchronousQueue<T> handoffQueue;

      // 添加连接
      // 将这个连接加入到共享队列 sharedList 中
      // 如果此时有线程在等待数据库连接,那么就通过 handoffQueue将这个连接分配给等待的线程
      add(){

      }

      // 获取连接
      // 首先查看线程本地存储是否有空闲连接
      //1.如果有,则返回一个空闲的连接;
      //2. 如果线程本地存储中无空闲连接,则从共享队列中获取。
      //3. 如果共享队列中也没有空闲的连接,则请求线程需要等待
      borrow(){

      }

      // 释放连接
      // 1.首先将数据库连接状态更改为 STATE_NOT_IN_USE
      // 2.之后查看是否存在等待线程
      // 如果有,则分配给等待线程;
      // 如果没有,则将该数据库连接保存到线程本地存储里
      require(){

      }
      1. 预分配到本地线程,减少了竞争
        1. 使用ThreadLocal存储分配到本地线程的连接
        2. 使用CAS防止共享队列sharedList中的连接重复分配