Java 字节数组 对比 低速 指针快速

简介: 如何才能快速比较两个字节数组呢?我将问题描述成下面的接口: public int compareTo(byte[] b1, int s1, int l1, byte[] b2, int s2,int l2);最直观的做法是同时遍历两个数组,两两比较。

如何才能快速比较两个字节数组呢?我将问题描述成下面的接口:

    public int compareTo(byte[] b1, int s1, int l1, byte[] b2, int s2,int l2);


最直观的做法是同时遍历两个数组,两两比较。

    public int compareTo(byte[] buffer1, int offset1, int length1,
      byte[] buffer2, int offset2, int length2) {
     // Short circuit equal case
     if (buffer1 == buffer2 && offset1 == offset2
      && length1 == length2) {
      return 0;
     }
     // Bring WritableComparator code local
     int end1 = offset1 + length1;
     int end2 = offset2 + length2;
     for (int i = offset1, j = offset2; i < end1 && j < end2; i++, j++) {
      int a = (buffer1[i] & 0xff);
      int b = (buffer2[j] & 0xff);
      if (a != b) {
    return a - b;
      }
     }
     return length1 - length2;
    }



如果事情这么简单就结束了,就没有意思了。

如果要提升性能,可以做循环展开等等优化,但这些优化应该依赖JVM来做,新的JVM可以做的很好。那还有什么办法可以提高性能呢?
可以将字节数组合并!!上面的例子中,每个byte被迫转型成了int,再比较。其实我们可以将8个byte转换成一个long,在比较long,这样效果会不会好些?用什么方法转换才是最优的?

    long sun.misc.Unsafe.getLong(Object o,int offset)


Java提供了一个本地方法,可以最快最好转换byte与long。该函数是直接访问一个对象的内存,内存地址是对象指针加偏移量,返回该地址指向的值。有人说Java很安全,不可以操作指针,所以有的时候性能也不高。其实不对,有了这个Unsafe类,Java一样也不安全。所以Unsafe类中的方法都不是public的,不过没关系,我们有反射。言归正传,下面是使用这种技术手段的实现代码。

    public int compareTo(byte[] buffer1, int offset1, int length1,
      byte[] buffer2, int offset2, int length2) {
     // Short circuit equal case
     if (buffer1 == buffer2 && offset1 == offset2
       && length1 == length2) {
      return 0;
     }
     int minLength = Math.min(length1, length2);
     int minWords = minLength / Longs.BYTES;
     int offset1Adj = offset1 + BYTE_ARRAY_BASE_OFFSET;
     int offset2Adj = offset2 + BYTE_ARRAY_BASE_OFFSET;
     
     /*
      * Compare 8 bytes at a time. Benchmarking shows comparing 8
      * bytes at a time is no slower than comparing 4 bytes at a time
      * even on 32-bit. On the other hand, it is substantially faster
      * on 64-bit.
      */
     for (int i = 0; i < minWords * Longs.BYTES; i += Longs.BYTES) {
      long lw = theUnsafe.getLong(buffer1, offset1Adj + (long) i);
      long rw = theUnsafe.getLong(buffer2, offset2Adj + (long) i);
      long diff = lw ^ rw;
     
      if (diff != 0) {
       if (!littleEndian) {
        return (lw + Long.MIN_VALUE) < (rw + Long.MIN_VALUE) ? -1
          : 1;
       }
     
       // Use binary search,一下省略若干代码
       .....
       return (int) (((lw >>> n) & 0xFFL) - ((rw >>> n) & 0xFFL));
      }
     }
     
     // The epilogue to cover the last (minLength % 8) elements.
     for (int i = minWords * Longs.BYTES; i < minLength; i++) {
      int result = UnsignedBytes.compare(buffer1[offset1 + i],
        buffer2[offset2 + i]);
      if (result != 0) {
       return result;
      }
     }
     return length1 - length2;
    }


实现比原来复杂了一些。但这次一次可以比较8个字节了。这种getLong函数和系统的字节序是紧紧相关的,如果是小端序操作起来有点麻烦,代码先省略掉。这样操作实际效果如何?我们需要对比测试下。对比两个1M的字节数组,如果使用第一个版本,每次比较平均需要2.5499ms,如果使用第二个版本,需要0.8359ms,提升了3倍。对应这种CPU密集型的操作,这样的提升可是很可观的。

如果要提升性能,使用Unsafe直接访问内存也是不错的选择。


目录
相关文章
|
6月前
|
存储 Oracle Java
Java11--ZGC--权衡--ZGC--GC术语--着色指针--多重映射--读屏障标记--重定位
Java11--ZGC--权衡--ZGC--GC术语--着色指针--多重映射--读屏障标记--重定位
127 0
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
|
5月前
|
Java 容器
双指针(JAVA语言)
双指针(JAVA语言)
双指针(JAVA语言)
|
5月前
|
Java
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
41 3
|
4月前
|
缓存 Java 数据库连接
Java演进问题之指针的间接获取现在对性能的影响变得更大如何解决
Java演进问题之指针的间接获取现在对性能的影响变得更大如何解决
|
6月前
|
存储 Java 开发者
探索Java开发中触发空指针异常的场景
作为一名后端开发者在Java编程的世界中,想必大家对空指针并不陌生,空指针异常是一种常见而又令人头疼的问题,它可能会在我们最不经意的时候突然出现,给我们的代码带来困扰,甚至导致系统的不稳定性,而且最可怕的是有时候不能及时定位到它的具体位置。针对这个问题,我们需要深入了解触发空指针异常的代码场景,并寻找有效的方法来识别和处理这些异常情况,而且我觉得空指针异常是每个Java开发者都可能面临的挑战,但只要我们深入了解它的触发场景,并采取适当的预防和处理措施,我们就能够更好地应对这个问题。那么本文就来分享一下实际开发中一些常见的触发空指针异常的代码场景,并分享如何有效地识别和处理这些异常情况。
99 1
探索Java开发中触发空指针异常的场景
|
6月前
|
传感器 数据采集 网络协议
Java串口通信:从十六进制字符串到字节数组的正确转换与发送
Java串口通信:从十六进制字符串到字节数组的正确转换与发送
281 4
|
6月前
|
安全 Java
Java为什么不让用指针?
总之,Java的设计目标之一是提供一个安全、稳定和易于开发的平台,通过禁止直接使用指针来实现这些目标。虽然指针可以提供更大的灵活性,但也带来了许多潜在的问题和安全风险。因此,Java采用了更高级的内存管理和安全性机制,以减少这些问题的发生。
60 1
|
6月前
|
Java
Java String 避免空指针的方法
Java String 避免空指针的方法
49 0
|
6月前
|
Rust 索引
Rust 编程小技巧摘选(6)
Rust 编程小技巧摘选(6)
81 1
Rust 编程小技巧摘选(6)