Richard Startin 在文章 A Quick Look at RoaringBitmap 中介绍 BitmapContainer 提到 Long.bitCount 在处理器支持的情况下,会被内联为调用指令 popcnt 实现。本文做简单记录,我们编写如下的代码:
1 | package me.tianshuang; |
Richard Startin 在文章 A Quick Look at RoaringBitmap 中介绍 BitmapContainer 提到 Long.bitCount 在处理器支持的情况下,会被内联为调用指令 popcnt 实现。本文做简单记录,我们编写如下的代码:
1 | package me.tianshuang; |
已知 -x = ~x + 1 ,我们可以使用 x & (-x) 得到二进制表示中最右侧的 1:
1 | 若 x 的二进制表示为: |
其中 JDK 中的 Integer.lowestOneBit 就采用了以上的方法实现:
1 | /** |
因为 x - 1 会使最低位 1 右侧的 0 全部变为 1 且最低位 1 同时变为 0,所以我们使用 x & (x - 1) 可以去除最低位的 1:
最近看 Richard Startin 关于 RoaringBitmap 的文章 A Quick Look at RoaringBitmap 时,提到 BitmapContainer 底层由 long[] 组成,内部使用了 Long.bitCount 计算容器的基数,此时会被优化为使用 CPU 指令 popcnt 实现,关于内联可以参考 JVM Intrinsics,本文先分析 bitCount 函数的实现机制,由于 Integer.bitCount 与 Long.bitCount 实现机制相同,就用 Integer.bitCount 进行分析。
首先从 Integer 的官方文档 Integer (Java Platform SE 8 ) 中,我们可以看到以下描述:
Implementation note: The implementations of the “bit twiddling” methods (such as highestOneBit and numberOfTrailingZeros) are based on material from Henry S. Warren, Jr.’s Hacker’s Delight, (Addison Wesley, 2002).
描述说明了 Integer 内部 bit 的相关方法实现来自于书籍 《Hacker’s Delight》,感兴趣的可以看看这本书籍。
1 | package me.tianshuang; |
以上的双重检查实现并不安全,原因为编译器可以重排序代码以使 Helper() 构造函数中的代码在写入 helper 变量后执行。如果发生了这样的情况,那么在构造线程写入 helper 变量之后,但在它实际完成对象构造之前,另一个线程可以在完成初始化之前出现并读取 helper,此时,该线程可能会看到对 helper 对象的非空引用,但会看到 helper 对象字段的默认值,而不是构造函数中设置的值。
最近看 Joshua Bloch 的访谈 More Effective Java With Google’s Joshua Bloch 时,其中提到单元测试不足以确保代码能够正常工作,举了二分搜索的例子,二分搜索的文章详见:Google AI Blog: Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken,本文在此作简要记录。
在 JDK 1.3.1_28 中 java.util.Arrays#binarySearch(int[], int) 的实现如下:
1 | /** |