代码之家  ›  专栏  ›  技术社区  ›  Adamski

对象vs字节[0]作为锁

  •  4
  • Adamski  · 技术社区  · 15 年前

    我之前评论过 this question (“为什么java.lang.Object不是抽象的?”)我听说用 byte[0] 因为锁比使用 java.lang.Object . 我肯定我在什么地方读过,但我记不起在哪里:有人知道这是不是真的吗?

    我怀疑是因为 字节[0] 需要的字节码比 Object ,尽管有人指出 字节[0] 需要额外的存储才能存储长度字段,因此听起来这可能会抵消任何好处。

    6 回复  |  直到 7 年前
        1
  •  13
  •   Michael Borgwardt    15 年前

    我有足够的好奇心去测试它。源代码:

    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 在你甚至可以测量总时间之前你的循环索引。

        2
  •  14
  •   user85421    15 年前

    使用java.lang.instrument.instrumentation检查大小:
    对象使用8个字节,字节[0]需要16个字节。(不确定大小是否以字节为单位,没有文档记录)。

    我还有时间创建一个对象和一个字节[0](2次):对象是赢家。

    (所有测试都在戴尔笔记本电脑、英特尔2GHz、Windos XP上运行)

    使用 client 虚拟机

    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 虚拟机

    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 为了赶上时代。

    * 定时器是我为Timming设计的一个类,它是 一个Java计时器的。

        3
  •  5
  •   Nathan Hughes    15 年前

    根据 Java Language Spec ,“所有类和数组类型都继承类对象的方法”,所以我不知道byte[0]如何才能更高效。

    这似乎是真的 first edition of the spec 以及:“数组类型的超类被视为对象”。

        4
  •  3
  •   Peter Lawrey    15 年前

    使用数组更容易混淆读取器imho。

    创建更少的对象比创建更多的对象更有效,因此如果它确实创建了足够多的对象,那么您创建的对象太多了。

        5
  •  2
  •   Community CDub    8 年前

    在Java中使用空数组作为锁对象的模式与性能几乎没有关系。

    空数组(偶数 new Object[0] )更可取,因为它们是可序列化的。通过使用 new Object() 你放弃了自动序列化。

    我习惯了做(从不在乎表现):

    private final Object lock = new Object[0];
    

    基元数组所需的字节码较少,因此可能 new byte[0] 会更好。

    见: Is it okay to to make the lock transient for a Serializable class?

        6
  •  1
  •   seh Alexei    15 年前

    你的问题提到了“效率”,但没有说明你追求的是什么样的效率。迄今为止的答案涉及 大小 但在两种表示中取消引用和使用内部锁的运行时开销应该相同。

    您还可以将使用内部锁的开销与使用 java.util.concurrent.locks.ReentrantLock 明确的或者你写在上面的 AbstractQueuedSynchronizer . 是否可以容忍对单独分配的对象的额外引用,需要对问题进行更详细的评估,但考虑到您已经在考虑 byte 数组,您必须考虑使用不同于 this 参考资料。