Объект против байта [0] как блокировки - PullRequest
4 голосов
/ 22 января 2010

Я ранее прокомментировал этот вопрос ("Почему java.lang.Object не является абстрактным?"), Заявив, что я слышал, что использование byte[0] в качестве блокировки было немного более эффективным, чем использование java.lang.Object. Я уверен, что где-то читал, но не могу вспомнить, где: Кто-нибудь знает, правда ли это на самом деле?

Я подозреваю, что это из-за того, что для byte[0] требуется чуть меньше байт-кода, чем для Object, хотя было отмечено, что byte[0] требует дополнительного хранилища для хранения поля длины, и это звучит так отрицать любую выгоду.

Ответы [ 6 ]

14 голосов
/ 24 января 2010

Использование java.lang.instrument.Instrumentation для проверки размеров:
Объект использует 8 байтов, байту [0] нужно 16 байтов. (не уверен, что размер указан в байтах, не задокументировано).

У меня также есть время для создания Объекта и байта [0] (2 раза): Объект - победитель.

(все тесты выполняются на ноутбуке DELL, Intel 2 ГГц, 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, чтобы узнать время.

* Таймер - это класс, который я создал для синхронизации, это , а не один из таймеров Java.

13 голосов
/ 23 января 2010

Мне стало достаточно любопытно, чтобы проверить это. Исходник:

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

Итак, вы правы в том, что байтовый код короче для массивов, потому что создание массива имеет свой собственный код операции JVM. Но что это значит? Не важно. Это виртуальная машина, поэтому нет абсолютно никакой гарантии, что меньшее количество инструкций байт-кода означает меньшую работу для реального физического процессора. Конечно, мы могли бы начать профилирование, но это было бы совершенно бессмысленно. Если вообще есть разница, не важно, в какую сторону, это никогда не будет иметь значения. Создание объектов невероятно быстро в наше время. Возможно, вам придется начать использовать long в качестве индекса цикла, прежде чем вы сможете измерить общее время.

5 голосов
/ 23 января 2010

Согласно Спецификация языка Java , «все типы классов и массивов наследуют методы класса Object», поэтому я не знаю, как байт [0] мог бы быть более эффективным.

Похоже, что это верно и для первого издания спецификации : «Суперкласс типа массива считается Object».

3 голосов
/ 23 января 2010

Использование массива с большей вероятностью запутает читателя ИМХО.

Создание меньшего количества объектов более эффективно, чем создание большего, поэтому, если оно когда-либо создало достаточно объектов, которые имело значение, вы создаете слишком много.

2 голосов
/ 16 ноября 2013

Шаблон использования пустого массива в Java в качестве объекта блокировки имеет мало общего с производительностью.

Пустые массивы (даже new Object[0]) предпочтительнее, потому что они сериализуемы. Используя new Object() вы отказываетесь от автоматической сериализации.

Я привык заниматься (никогда не заботясь о производительности):

private final Object lock = new Object[0];

Для создания примитивных массивов требуется меньше байт-кода, поэтому, возможно, new byte[0] будет «лучше».

См .: Можно ли сделать блокировку временной для класса Serializable?

1 голос
/ 24 января 2010

Ваш вопрос упоминает "эффективность", но не говорит о том, какую эффективность вы преследуете. Пока что ответы касаются размера объектов, но затраты времени разыменования и использования встроенной блокировки в любом представлении должны быть одинаковыми.

Вы также можете сравнить накладные расходы на использование встроенных блокировок с использованием java.util.concurrent.locks.ReentrantLock в явном виде или с тем, который вы пишете себе поверх AbstractQueuedSynchronizer. Если вы можете допустить дополнительную ссылку на отдельно выделенный объект, для оценки требуется более подробная информация о вашей проблеме, но, учитывая, что вы уже рассматриваете массивы byte, вы должны рассмотреть возможность использования встроенной блокировки, отличной от вашей ссылки this .

...