对象与 byte[0] 作为锁
-
22-09-2019 - |
题
我之前评论过 这个问题 (“为什么 java.lang.Object 不是抽象的?”)指出我听说使用 byte[0]
因为锁比使用锁稍微更有效 java.lang.Object
. 。我确信我在某处读过这篇文章,但我不记得在哪里:有谁知道这是否属实?
我怀疑这是由于实例化 byte[0]
需要的字节码略少于 Object
, ,尽管有人指出 byte[0]
需要额外的存储空间才能存储长度字段,因此听起来这可能会抵消任何好处。
解决方案
我好奇够对其进行测试。源代码:
public class Test {
public static Object returnObject() {
return new Object();
}
public static byte[] returnArray(){
return new byte[0];
}
}
字节码:
public static java.lang.Object returnObject();
Code:
0: new #2; //class java/lang/Object
3: dup
4: invokespecial #1; //Method java/lang/Object."<init>":()V
7: areturn
public static byte[] returnArray();
Code:
0: iconst_0
1: newarray byte
3: areturn
所以你在字节码是数组较短,因为阵列创作有其自己的JVM操作码的权利。但是,这是什么意思?真的没什么。这是一个虚拟机,所以绝对不能保证较少的字节码指令意味着实际的物理CPU更少的工作。我们可以开始上课的分析,但是这将是毫无意义的。如果在所有的差异,无论哪一种方式,它永远不会不管。对象的创建是令人难以置信的快速时下。你可能不得不开始使用long
您的循环索引之前,你甚至可以测量的总时间。
其他提示
使用java.lang.instrument.Instrumentation查询的大小:点击 对象使用8个字节,字节[0]需要16个字节。 (如果不知道大小是以字节为单位,没有记录)。
我也得到了创建一个对象和一个字节[0](2次)的时间:对象是赢家。
(所有测试上的DELL笔记本,英特尔的2GHz,WINDOS XP运行)
使用client
VM
java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode)
an implementation-specific approximation of the amount of storage
Object = 8
byte[0] = 16
time to create 1000000000 instances
Object: elapsed=11,140 cpu=9,766 user=9,703 [seconds]
byte[0]: elapsed=18,248 cpu=15,672 user=15,594 [seconds]
time to create 1000000000 instances
Object: elapsed=11,135 cpu=9,828 user=9,750 [seconds]
byte[0]: elapsed=18,271 cpu=15,547 user=15,469 [seconds]
使用server
VM
java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode)
an implementation-specific approximation of the amount of storage
Object = 8
byte[0] = 16
time to create 1000000000 instances
Object: elapsed=8,441 cpu=7,156 user=7,125 [seconds]
byte[0]: elapsed=11,237 cpu=8,609 user=8,500 [seconds]
time to create 1000000000 instances
Object: elapsed=8,501 cpu=7,234 user=7,156 [seconds]
byte[0]: elapsed=11,023 cpu=8,688 user=8,641 [seconds]
我将留在new Object()
,不仅因为可读性的:-)
的代码
public class ObjectArrayCompare {
private static Object o;
public static void main(String[] args) {
Instrumentation instr = InstrumentationAgent.getInstrumentation();
if (instr == null) {
System.err.println("No Instrumentation, use \"-javaagent:Instrumentation.jar\"");
return;
}
System.out.println();
System.out.println("an implementation-specific approximation of the amount of storage");
System.out.println("Object = " + instr.getObjectSize(new Object()));
System.out.println("byte[0] = " + instr.getObjectSize(new byte[0]));
System.out.println();
final int MAX = (int) 1.0e9;
Timer timer;
Times times;
for (int j = 0; j < 2; j++) {
System.out.println("time to create " + MAX + " instances");
timer = new Timer();
for (int i = 0; i < MAX; i++) {
o = new Object();
}
times = timer.times();
System.out.println("Object: " + times);
timer = new Timer();
for (int i = 0; i < MAX; i++) {
o = new byte[0];
}
times = timer.times();
System.out.println("byte[0]: " + times);
System.out.println();
}
}
}
定时器 * 用途ThreadMXBean
得到倍。
* 的定时器I类为timming做,这是不会在Java定时器的。的
这是一个使用的阵列更容易混淆读者IMHO。
创建对象少比创造更多更有效,因此,如果它曾经做过产生足够的对象,它要紧,你在创造太多了。
使用Java中的空数组作为锁定对象的图案具有一点做与性能。
,因为它们是可序列化的空阵列(甚至new Object[0]
)是优选的。通过使用new Object()
你放弃自动序列化。
我习惯做(约性能从未关心):
private final Object lock = new Object[0];
原始阵列花费更少的字节码来创建,所以也许new byte[0]
将是“更好”。
你的问题提到了“效率”,但没有说你追求什么样的效率。迄今为止的答案涉及 尺寸 的对象,但在任一表示中取消引用和使用内在锁的运行时成本应该是相同的。
您还可以比较使用内在锁和使用 java.util.concurrent.locks.ReentrantLock
明确地或您自己写在上面 AbstractQueuedSynchronizer
. 。您是否可以容忍对单独分配的对象的额外引用需要更详细的问题来评估,但考虑到您已经在考虑 byte
数组,您必须考虑使用与您的数组不同的内在锁 this
参考。