Правильно синхронизация равняется () в Java

Ни один из DOMNodeInserted или события DOMNodeInsertedIntoDocument не поддерживается в IE. Другое отсутствие от IE [только] показывает DOM, функция compareDocumentPosition, которая разработана, чтобы сделать то, что предлагает ее имя.

Что касается предложенного решения, я думаю, что там не лучше один (если Вы не делаете некоторые злые шутки как перезапись собственных членских реализаций DOM)

кроме того, исправляя заголовок вопроса: динамично созданный Элемент является частью DOM с момента, это создается, это может быть добавлено к фрагменту документа, или к другому элементу, но это не могло бы быть добавлено к документу.

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

11
задан Philipp 28 October 2009 в 10:29
поделиться

12 ответов

Попытка синхронизировать равняется и hashCode внутри объекта не будет работать должным образом. Рассмотрим случай HashMap , который использует hashCode , чтобы обнаружить, в каком «ведре» будет находиться объект, а затем использует равно для последовательного поиска всех объектов в ведро.

Если объектам разрешено видоизменяться таким образом, что изменяются результаты hashCode или равно , вы можете получить сценарий, в котором HashMap вызывает хэш-код . Он получает блокировку, получает хэш и снова освобождает блокировку. HashMap затем переходит к вычислению того, какое «ведро» использовать. Но до того, как HashMap сможет получить блокировку, если кто-то другой захватит блокировку и изменит объект так, что равно , станет несовместимым с предыдущим значением hashCode . Это приведет к катастрофическим результатам.

hashCode и методы equals используются во многих местах и ​​являются ядром API коллекций Java. Было бы полезно переосмыслить структуру вашего приложения, не требующего синхронизированного доступа к этим методам. Или, по крайней мере, не синхронизировать сам объект.

hashCode и методы equals используются во многих местах и ​​являются ядром API коллекций Java. Было бы полезно переосмыслить структуру вашего приложения, не требующего синхронизированного доступа к этим методам. Или, по крайней мере, не синхронизировать сам объект.

hashCode и методы equals используются во многих местах и ​​являются ядром API коллекций Java. Было бы полезно переосмыслить структуру вашего приложения, не требующего синхронизированного доступа к этим методам. Или, по крайней мере, не синхронизировать сам объект.

9
ответ дан 3 December 2019 в 03:18
поделиться

Чтение и запись в int переменных уже являются атомарными, поэтому нет необходимости синхронизировать геттер и сеттер (см. http: //java.sun. com / docs / books / tutorial / essential / concurrency / atomic.html ).

Аналогично, вам не нужно синхронизировать здесь равно . Хотя вы можете запретить другому потоку изменять одно из значений i во время сравнения, этот поток просто блокируется до тех пор, пока метод равно не будет завершен, и сразу же изменит его.

-2
ответ дан 3 December 2019 в 03:18
поделиться

Не использовать синхронизацию. Подумайте о неизменяемых бобах.

0
ответ дан 3 December 2019 в 03:18
поделиться

Всегда блокируйте их в одном и том же порядке, в одном из способов вы можете определить порядок по результатам System.identityHashCode (Object)

Изменить, чтобы включить комментарий:

Лучшее решение для редкого случая равенства идентификаторовHashCodes требует более подробной информации о том, какая еще происходит блокировка этих объектов.

Все требования к множественной блокировке объектов должны использовать один и тот же процесс разрешения.

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

1
ответ дан 3 December 2019 в 03:18
поделиться

Как указывает Джейсон Дэй, целочисленные сравнения уже атомарны, поэтому синхронизация здесь излишняя. Но если вы просто строили упрощенный пример и в реальной жизни думаете о более сложном объекте:

Прямой ответ на ваш вопрос: убедитесь, что вы всегда сравниваете элементы в последовательном порядке. Неважно, какой это порядок, если он согласован. В таком случае System.identifyHashCode обеспечит порядок, например:

public boolean equals(Object o)
{
  if (this==o)
    return true;
  if (o==null || !o instanceof Sync)
    return false;
  Sync so=(Sync) o;
  if (System.identityHashCode(this)<System.identityHashCode(o))
  {
    synchronized (this)
    {
      synchronized (o)
      {
         return equalsHelper(o);
      }
    }
  }
  else
  {
    synchronized (o)
    {
      synchronized (this)
      {
        return equalsHelper(o);
      }
    }
  }
}

Затем объявит equalsHelper private и позволит ему выполнить реальную работу по сравнению.

(Но ничего себе, это много кода для такой тривиальной проблемы .)

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

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

Если это реальная проблема в проекте, над которым вы работаете, серьезной альтернативой, которую следует рассмотреть, было бы сделать объект неизменяемым. Подумайте о String и StringBuilder. Вы можете создать объект SyncBuilder, который позволит вам выполнять любую работу, необходимую для создания одной из этих вещей, а затем иметь объект Sync, состояние которого устанавливается конструктором и никогда не может измениться. Создайте конструктор, который принимает SyncBuilder и устанавливает его состояние для соответствия или наличия метода SyncBuilder.toSync. Так или иначе,

0
ответ дан 3 December 2019 в 03:18
поделиться

Правильная реализация equals () и hashCode () требуется для различных вещей, таких как структуры хеширования данных, и поэтому у вас нет реальной возможности там. С другой стороны, equals () и hashCode () - это просто методы с теми же требованиями к синхронизации, что и другие методы. У вас все еще есть проблема с тупиком, но она не связана с тем фактом, что она equals () вызывает ее.

0
ответ дан 3 December 2019 в 03:18
поделиться

(я предполагаю, что здесь вас интересует общий случай, а не только обернутые целые числа.)

Вы не можете запретить двум потокам вызывать set ... методы в произвольном порядке. Таким образом, даже когда один поток получает (действительный) истинный от вызова .equals ( ... ) , этот результат может быть немедленно признан недействительным другим потоком, который вызывает устанавливает ... на один из объектов. IOW результат означает только то, что значения были равны в момент сравнения.

Таким образом, синхронизация защитит от случая, когда обернутое значение находится в несогласованном состоянии, когда вы пытаетесь выполнить сравнение (например, два int -размерные половинки обернутого long обновляются последовательно).

1
ответ дан 3 December 2019 в 03:18
поделиться

Если уже сказано достаточно, поля, которые вы используете для hashCode (), equals () или compareTo (), должны быть неизменяемыми, желательно окончательными. В этом случае вам не нужно их синхронизировать.

Единственная причина для реализации hashCode () состоит в том, чтобы объект можно было добавить в коллекцию хэшей, и вы не можете корректно изменить hashCode () объекта, который был добавлен в такую ​​коллекцию.

3
ответ дан 3 December 2019 в 03:18
поделиться

Где смысл синхронизации equals (), если результат не гарантирован чтобы быть истинным после того, как синхронизация была оставлена:

if (o1.equals(o2)) {
  // is o1 still equal to o2?
}

Следовательно, вы можете просто синхронизировать вызовы getI () внутри равных один за другим, не изменяя вывод - это просто больше не действует.

Вам всегда придется синхронизировать весь блок :

synchronized(o1) {
  synchronized(o2) {
    if (o1.equals(o2)) {
      // is o1 still equal to o2?
    }
  }
}

По общему признанию, вы все равно столкнетесь с той же проблемой, но, по крайней мере, с синхронизацией в нужный момент;)

6
ответ дан 3 December 2019 в 03:18
поделиться

Зачем синхронизировать? Каков вариант использования, когда имеет значение одно, если они изменяются во время сравнения, и не имеет значения, если они изменяются сразу после того, как код запускается в зависимости от равенства. (т.е. если у вас есть код, в зависимости от equlity, что произойдет, если значения станут неравными до или во время этого кода)

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

7
ответ дан 3 December 2019 в 03:18
поделиться

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

Если вы заблокируете оба ] этот и другой объект одновременно вы действительно рискуете попасть в тупик. Но я сомневаюсь, что вам нужно это делать. Вместо этого, я думаю, вам следует реализовать equals (Object) следующим образом:

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Sync other = (Sync) obj;
    return this.getI() == other.getI();
}

Это не гарантирует, что два объекта имеют одинаковое значение i одновременно, но вряд ли это будет иметь какое-либо практическое значение. В конце концов, даже если бы у вас была эта гарантия, вам все равно пришлось бы справляться с проблемой, что два объекта могут перестать быть равными к тому времени, когда будет возвращен вызов равняется . (Это касается @ s!)

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

// In same class as above ...
public synchronized void frobbitt(Object other) {
    if (this.equals(other)) {
        ...
    }
}

Теперь, если два потока вызывают a.frobbitt (b) и b.frobbitt (a) соответственно, существует риск взаимоблокировки.

(Однако вы необходимо вызвать getI () или объявить i как изменчивый , в противном случае equals () может увидеть устаревшее значение i , если оно было недавно обновлено другим потоком.)

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

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

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

1
ответ дан 3 December 2019 в 03:18
поделиться

Вы пытаетесь определить "равно" и "hashCode" на основе содержимого для изменяемого объекта. Это не только невозможно: в этом нет смысла. Согласно

http://java.sun.com/javase/6/docs/api/java/lang/Object.html

и "equals", и "hashCode" должны быть согласованными: возвращать одно и то же значение. для последовательных вызовов одного и того же объекта (ов). Изменчивость по определению предотвращает это. Это не просто теория: многие другие классы (например, коллекции) зависят от объектов, реализующих правильную семантику для equals / hashCode.

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

2
ответ дан 3 December 2019 в 03:18
поделиться
Другие вопросы по тегам:

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