随着 JDK 的发展以及 JIT 的不断优化,我们很多时候都可以写读起来易读但是看上去性能不高的代码了,编译器会帮我们优化代码。之前大学里面学单片机的时候,由于内存以及处理器性能都极其有限(可能很多时候考虑内存的限制优先于处理器),所以很多时候,利用位运算来节约空间或者提高性能,那么这些优秀的思想,放到目前的 Java 中,是否还有必要这么做呢?我们逐一思考与验证下(其实这也是一个关于 Premature optimization 的界定的思考)。
引言随着 JDK 的发展以及 JIT 的不断优化,我们很多时候都可以写读起来易读但是看上去性能不高的代码了,编译器会帮我们优化代码。之前大学里面学单片机的时候,由于内存以及处理器性能都极其有限(可能很多时候考虑内存的限制优先于处理器),所以很多时候,利用位运算来节约空间或者提高性能,那么这些优秀的思想,放到目前的 Java 中,是否还有必要这么做呢?我们逐一思考与验证下(其实这也是一个关于 Premature optimization 的界定的思考)
1. 乘法与左移位左移一位,相当于乘以 2,左移 n 位,相当于乘以 2 的 n 次方。
1 >> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;n += 1; //大于 N 的最小的 2 的 N 次方n = n >>> 1; //小于 N 的最大的 2 的 N 次方
如果有兴趣,可以看一下 Java 的 ForkJoinPool 类的构造器,其中的 WorkQueue 大小,就是通过这样的转换得来的。
5. 交换两个数字这个在单片机编程中经常会使用这个位运算性质:一个数字异或自己为零,一个数字异或 0 为自己本身。那么我们就可以利用这个性质交换两个数字。
假设有数字 x,y。我们有x^y^y = x^(y^y)= x^0 = x
还有x^y^y^x^y = 0^y = y
那么我们可以利用:
x = x ^ y;y = x ^ y; //代入后就是 x^y^yx = x ^ y; //代入后就是 x^y^y^x^y
这个方法虽然很巧妙,但是是一种时间换空间的方式; 我们常用的利用另一个变量实现交换是一种空间换时间的方式,来对比下性能:
@Benchmark@Warmup(iterations = 0)@Measurement(iterations = 300)public int swap_1() { int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE / 2; int z = x; x = y; y = z; return x + y;}@Benchmark@Warmup(iterations = 0)@Measurement(iterations = 300)public int swap_2() { int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE / 2; x ^= y; y ^= x; x ^= y; return x + y;}
结果:
Benchmark Mode Cnt Score Error UnitsBitUtilTest.swap_1 thrpt 300 267787894.370 ± 559479133.393 ops/sBitUtilTest.swap_2 thrpt 300 265768807.925 ± 387039155.884 ops/s
测试来看,性能差异并不明显,利用位运算减少了空间占用,减少了 GC,但是交换减少了 cpu 运算,但是 GC 同样是消耗 cpu 计算,所以,很难界定。目前还是利用中间变量交换的更常用,也更易读一些。
6. bit 状态位我们为了节省空间,尝尝利用一个数字类型(例如 long 类型)作为状态数,每一位代表一个状态是 true 还是 false。假设我们使用 long 类型,则一个状态数可以最多表示 64 个属性。代码上一般这么写:
public static class Test { //如果你的 field 是会被并发修改访问,那么最好还是加上缓存行填充防止 false sharing @jdk.internal.vm.annotation.Contended private long field; private static final long SWITCH_1_MASK = 1; private static final long SWITCH_2_MASK = 1
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?