Эквивалентный код, например, синхронизация метода в Java

Совершенно ясно, как это?

for (key, value) in col_read {
    print(key)
    for (innerKey, innerValue) in value {
        print(innerKey)
        for number in innerValue {
            print(number)
        }
    } 
}

PS - Используйте lowerCamelCase для имен переменных, как упомянуто в Рекомендации по разработке API [ 111].

8
задан Community 23 May 2017 в 10:27
поделиться

6 ответов

Они эквивалентны в функции, хотя компиляторы, которые я протестировал (Java 1.6.0_07 и Eclipse 3.4) генерируют другой байт-код. Первое генерирует:

// access flags 33
public synchronized someMethod()V
  RETURN

Второе генерирует:

// access flags 1
public someMethod()V
  ALOAD 0
  DUP
  MONITORENTER
  MONITOREXIT
  RETURN

(Благодаря ASM для печати байт-кода).

Таким образом, различие между ними сохраняется к уровню байт-кода, и это до JVM для создания их поведения тем же. Однако они действительно имеют тот же функциональный эффект - посмотрите пример в Спецификации языка Java.

Нужно отметить, что, если метод переопределяется в подклассе, что это не обязательно синхронизируется - таким образом, нет никакого различия в этом отношении также.

Я также запустил тест для блокирования доступа попытки потока монитор в каждом случае для сравнения то, на что их отслеживания стека будут похожи в дампе потока, и они оба содержали рассматриваемый метод, таким образом, нет никакого различия там также.

13
ответ дан 5 December 2019 в 06:39
поделиться

Я сделал исходный комментарий, что операторы идентичны.

В обоих случаях первая вещь, которая происходит, состоит в том, что вызывающий поток попытается получить текущий объект (значение, this') монитор.

Я не знаю о другом байт-коде, я буду рад услышать различие. Но на практике, они на 100% идентичны.

Править: я собираюсь разъяснить это, поскольку некоторые люди здесь поняли его превратно. Рассмотрите:

public class A {
    public synchronized void doStuff()
    {
        // do stuff
    }
}

public class B extends A {
    public void doStuff()
    {
        // do stuff
        // THIS IS OVERRIDE!
    }
}

В этом случае doStuff() в классе B все еще переопределяет doStuff() в классе A даже при том, что это не синхронизируется.

Синхронизируемое ключевое слово никогда не является частью контракта! Не для подклассов, не для интерфейсов, не для абстрактных классов.

7
ответ дан 5 December 2019 в 06:39
поделиться

Да. Используя синхронизируемое ключевое слово на использовании метода экземпляра 'это' как монитор, также с помощью него на методе класса (статический метод) использует Объект класса класса (Foo.class).

Таким образом, можно синхронизировать все методы, и в то же время, синхронизировать его с фрагментом кода в другом методе с помощью синхронизируемого стиля блока.

2
ответ дан 5 December 2019 в 06:39
поделиться
MyObject myObjectA;
MyObject myObjectB;

public void someMethod() {
  synchronized (this) {
    //stuff
  }
}

public void someMethodA() {
  synchronized (myObjectA) {
    //stuff
  }
}

public void someMethodB() {
  synchronized (myObjectB) {
    //stuff
  }
}

В этом случае:

  • someMethod блоки весь класс
  • someMethodA блоки myObjectA только
  • someMethodB блоки myObjectB только
  • someMethodA и someMethodB может быть вызван одновременно
-1
ответ дан 5 December 2019 в 06:39
поделиться

Я не вижу функционального различия - оба синхронизируют их все тела метода на (этом). Как сделал человека, который прокомментировал, что они отличаются, выравнивают по ширине их оператор?

0
ответ дан 5 December 2019 в 06:39
поделиться

Я сделал исходный комментарий. Мой комментарий был то, что они логически эквивалентны, но компилируют в другой байт-код.

Я не добавил ничто больше для выравнивания по ширине его в то время, потому что нет очень для выравнивания по ширине действительно - они просто компилируют в другой байт-код. Если Вы объявляете метод, как синхронизируется, то та синхронизация является частью определения метода. Синхронизируемый блок в рамках метода не является частью определения метода, но вместо этого включает отдельные байт-коды, чтобы получить и выпустить монитор, поскольку один из плакатов выше проиллюстрировал. Строго говоря они - немного отличающиеся вещи, хотя к полной логике Вашей программы, они эквивалентны.

Когда это имеет значение? Ну, на самом современном настольном VMs, почти никогда. Но например:

  • VM мог в принципе сделать оптимизации в одном случае, но не другом
  • существуют некоторые оптимизации JIT-компилятора, где количество байт-кодов в методе взято в качестве критерия какой оптимизации сделать
  • VM без JIT-компилятора (по общему признанию немногие в наше время, но возможно на более старом мобильном устройстве?) будет иметь больше байт-кодов для обработки на каждом вызове
4
ответ дан 5 December 2019 в 06:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: