我开了 100 个线程用同一个 id 分别去请求这两个方法,把这 100 次方法执行时间的平均值取出来,并且相同的方法重复做了三次得到结果: a: 24907.9ms, b: 24831.1ms ,看结果方法 b 好一点,但这个差距是不是很小啊?
@Controller
@RequestMapping("/bench/")
public class BenchController {
private static Object[] lockObj;
private static AtomicReference<Integer>[] locks;
static {
lockObj = new Object[100];
for (int i = 0; i < lockObj.length; i++) {
lockObj[i] = new Object();
}
locks = new AtomicReference[100];
for (int i = 0; i < locks.length; i++) {
locks[i] = new AtomicReference<Integer>(null);
}
}
@RequestMapping("a")
@ResponseBody
public long a(int id) throws Exception {
long start = System.currentTimeMillis();
int index = id % 100;
synchronized (lockObj[index]) {
Thread.sleep(500);
}
long result=System.currentTimeMillis() - start;
System.out.println(result);
return result;
}
@RequestMapping("b")
@ResponseBody
public long b(int id) throws Exception {
long start = System.currentTimeMillis();
int index = id % 100;
while (!locks[index].compareAndSet(null, id)) {
}
Thread.sleep(500);
locks[index].compareAndSet(id, null);
long result=System.currentTimeMillis() - start;
System.out.println(result);
return result;
}
}
1
sorra 2017-04-22 14:44:43 +08:00
sleep 是有误差的,你的测试可能是无效的。可以在方法内循环大量次数来测试,也许能有效果
|
2
sagaxu 2017-04-22 14:59:09 +08:00
sleep 一下要 500ms , lock 一下是不到 1ms 的, sleep 本身的误差已经远大于 lock 的开销。结论,这测试就是胡乱测的。 JVM 的 jit 预热,这里更加看不到了。
|
4
Ouyangan 2017-04-22 15:22:57 +08:00
二楼的说法靠谱
记得 JDK1.6 的 JIT C2 策略阈值是 10000 , 楼主可以先在静态代码块中先跑个 10000 次 ,触发 JIT 后再做比较 . 推荐补补 JVM 类执行机制的知识 |
5
hyperdak 2017-04-22 15:31:45 +08:00 3
micro benchmark 会被 gc 、 jit 、不正确的代码影响,你得到结果本身就是错的。
正确的 java benchmark 要用 JMH 这种套件来做,它包含了预热和防止代码被 DCE 。在正确使用 JMH 的时候,你就可以得到一个正确的 benchmark 结果了 |
6
0915240 2017-04-22 17:02:52 +08:00
既然是要获取基准测试并且感知到小差距,建议换到用 jmh 试试看。
|