Object vs byte [0] as lock

I commented earlier on this question ("Why is java.lang.Object not abstract?") Stating that I heard that using byte[0] as, locking was a little more efficient than using java.lang.Object . I'm sure I read it somewhere, but I can’t remember where: Does anyone know if this is true?

I suspect that due to the byte[0] instance, a little less byte code is required than Object , although it was pointed out that byte[0] needed additional storage to store the length field, and therefore it sounds like this, to deny any benefit.

+4
source share
6 answers

I was curious to check this out. Source:

 public class Test { public static Object returnObject() { return new Object(); } public static byte[] returnArray(){ return new byte[0]; } } 

Bytecode:

 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 

So, you're right that the bytecode is shorter for arrays, because creating an array has its own JVM operation code. But what does this mean? Not important. This is a virtual machine, so there is absolutely no guarantee that fewer bytecode instructions mean less work for a real physical processor. Of course, we could start profiling, but that would be completely pointless. If there is a difference at all, no matter how, it will never matter. Creating objects is incredibly fast right now. You may have to start using long for your loop index before you can even measure the total time.

+13
source

Using java.lang.instrument.Instrumentation to check sizes:
The object uses 8 bytes, byte [0] - 16 bytes. (not sure if size in bytes, not documented).

I also got time to create the object and bytes [0] (2 times): the object is the winner.

(all tests are performed on a DELL laptop, Intel 2 GHz, Windos XP)

Using 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] 

Using 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] 

I will stay with new Object() not only because of readability :-)

The code

 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(); } } } 

The timer * uses ThreadMXBean to get the time.

* Timer is the class I made for timming, it is not one of the Java timers.

+14
source

According to the Java Language Spec , "all types of classes and arrays inherit methods from the Object class," so I don’t know how byte [0] could work to be more efficient.

This is similar to the first release of the specification : "The superclass of an array type is considered an object."

+5
source

Using an array is more likely to confuse the reader IMHO.

Creating smaller objects is more efficient than creating more, so if it has ever created enough of the objects that it mattered, you create too much.

+3
source

Your question mentions "effectiveness" but does not say what kind of efficiency you are achieving. The answers so far relate to the size of the objects, but the time taken to dereference and use the built-in lock in any view should be the same.

You can also compare the overhead associated with using built-in locks using java.util.concurrent.locks.ReentrantLock explicitly or you write yourself on top of AbstractQueuedSynchronizer . If you can tolerate an additional reference to the selected object, more detailed information about your problem is required for evaluation, but given that you are already considering byte arrays, you should consider using a built-in lock different from your this reference.

+1
source

The pattern of using an empty array in Java as a lock object has little to do with performance.

Empty arrays (even new Object[0] ) are preferred because they are serializable. Using new Object() , you refuse automatic serialization.

I'm used to working (never caring about performance):

 private final Object lock = new Object[0]; 

Primitive arrays take less bytecode to create, so perhaps new byte[0] will be "better."

See: Is it possible to make a lock transient for a Serializable class?

+1
source

Source: https://habr.com/ru/post/1299155/


All Articles