Рекурсивная блокировка (взаимное исключение) по сравнению с нерекурсивной блокировкой (взаимное исключение)

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

175
задан jotik 13 May 2016 в 07:53
поделиться

4 ответа

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

Однако , существуют другие соображения в действии здесь также.

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

Другое свойство, которое идет со смыслом владения во взаимном исключении, является способностью поддерживать наследование приоритета. Поскольку ядро может отследить поток, владеющий взаимным исключением, и также идентификационные данные всего блокировщика (блокировщиков), в приоритете распараллелили систему, становится возможно нарастить приоритет потока, который в настоящее время владеет взаимным исключением к приоритету самого высокого приоритетного потока, который в настоящее время блокируется на взаимном исключении. Это наследование предотвращает проблему смены приоритетов, которая может произойти в таких случаях. (Обратите внимание, что не все системы поддерживают наследование приоритета на таких взаимных исключениях, но именно другая функция становится возможной через понятие владения).

, Если Вы обращаетесь к классическому ядру VxWorks RTOS, они определяют три механизма:

  • взаимное исключение - рекурсия поддержек и дополнительно наследование приоритета
  • двоичный семафор - никакая рекурсия, никакое наследование, простое исключение, берущий и дающий не должны быть тем же потоком, широковещательно передавать выпуск, доступный
  • семафор подсчета - никакая рекурсия или наследование, действия как когерентный счетчик ресурса от любого желаемого начального количества, не распараллеливают только блок, где сеть говорит против ресурса, нуль.

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

146
ответ дан Tall Jeff 23 November 2019 в 20:26
поделиться

Ответ не эффективность. Неповторно используемые взаимные исключения ведут для лучше кодирования.

Пример: A:: нечто () получает блокировку. Это тогда называет B:: панель (). Это хорошо работало, когда Вы записали его. Но когда-то позже кто-то изменяет B:: панель () для вызова A:: baz (), который также получает блокировку.

ну, если у Вас нет рекурсивных взаимных исключений, это заходит в тупик. Если у Вас действительно есть они, это работает, но это может повредиться. A:: нечто (), возможно, оставило объект в непоследовательном состоянии перед тем, чтобы называть панель (), при условии, что baz () не мог быть выполнен, потому что это также получает взаимное исключение. Но это, вероятно, не должно работать! Человек, который записал A:: нечто () предположило, что никто не мог назвать A:: baz () одновременно - это - вся причина, что оба из тех методов получили блокировку.

правильная умственная модель для использования взаимных исключений: взаимное исключение защищает инвариант. Когда взаимное исключение сохранено, инвариант может измениться, но прежде, чем выпустить взаимное исключение, инвариант восстановлен. Повторно используемые блокировки опасны, потому что во второй раз Вы получаете блокировку, Вы не можете быть уверены, что инвариант больше верен.

, Если Вы довольны повторно используемыми блокировками, это - только потому, что Вы не должны были отлаживать проблему как это прежде. Java имеет неповторно используемые блокировки в эти дни в java.util.concurrent.locks, между прочим.

119
ответ дан David Harkness 23 November 2019 в 20:26
поделиться

правильная умственная модель для использования взаимных исключений: взаимное исключение защищает инвариант.

, Почему Вы уверены, что это - действительно правильная умственная модель для использования взаимных исключений? Я думаю, что правильная модель защищает данные, но не инварианты.

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

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

14
ответ дан 23 November 2019 в 20:26
поделиться

Как написал сам Дэйв Бутенхоф :

«Самая большая из всех больших проблем с рекурсивными мьютексами заключается в том, что они побуждают вас полностью забыть о вашей схеме блокировки и сфера. Это смертельно. Злой. Это «пожиратель ниток». Вы держите замки для в кратчайшие сроки. Период. Всегда. Если ты звонишь что-то с замком, удерживаемым просто потому, что вы не знаете, что он удерживается, или потому что вы не знаете, нужен ли мьютекс вызываемому, тогда вы держал его слишком долго. Вы целите дробовик в свое приложение и нажатие на курок. Вы, вероятно, начали использовать потоки, чтобы получить параллелизм; но вы просто ПРЕДОТВРАТИТЕ параллелизм ".

88
ответ дан 23 November 2019 в 20:26
поделиться
Другие вопросы по тегам:

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