Czy gettery i settery powinny być zsynchronizowane?

private double value;

public synchronized void setValue(double value) {
    this.value = value;
}
public double getValue() {
    return this.value;
}

Czy w powyższym przykładzie jest sens synchronizacji gettera?

Author: Lii, 2012-07-12

4 answers

Myślę, że najlepiej przytoczyć współbieżność Javy w praktyce tutaj:

Powszechnym błędem jest zakładanie, że synchronizacja musi być używana tylko podczas zapisu do współdzielonych zmiennych; po prostu nie jest to prawdą.

Dla każdej zmiennej zmiennej stanu, do której dostęp może uzyskać więcej niż jeden thread, Wszystkie dostępy do tej zmiennej muszą być wykonane z tym samym zamek utrzymany. W tym przypadku mówimy, że zmienna jest strzeżona przez zamek.

W brak synchronizacji powoduje, że kompilator, procesor i środowisko uruchomieniowe mogą wykonywać dziwne rzeczy w kolejności wykonywania operacji. Próby rozumowania o kolejności, w jakiej "muszą" nastąpić działania pamięci w niewygodnie zsynchronizowanych programach wielowątkowych, będą prawie na pewno błędne.

Normalnie nie trzeba być tak ostrożnym z prymitywami, więc jeśli to będzie int lub boolean to może być tak:

Gdy wątek czyta zmienna bez synchronizacji, może widzieć nieświeżą wartość, ale przynajmniej widzi wartość, która została faktycznie umieszczona tam przez jakiś wątek, a nie jakąś losową wartość.

Nie jest to jednak prawdą dla operacji 64-bitowych, na przykład na long lub double, Jeśli nie są zadeklarowane volatile:

Model pamięci Java wymaga pobierania i operacje magazynowe mają być atomowe, ale dla nieulotnych długich i podwójnych zmiennych, JVM może traktować 64-bitowy odczyt lub zapis jako dwa oddzielne 32-bitowe operacje. Jeśli odczyty i zapisy występują w różnych wątków, dlatego możliwe jest odczytanie nieulotnej długości i uzyskanie back the high 32 bits of one value and the low 32 bits of another.

Dlatego nawet jeśli nie dbasz o stare wartości, nie jest to bezpieczne w użyciu współdzielone zmienne długie i podwójne w programach wielowątkowych chyba że są uznane za lotne lub strzeżone przez zamek.

 70
Author: Konrad Reiche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-12 20:36:59

Pozwól, że pokażę Ci na przykładzie, jaki jest legalny sposób kompilacji kodu przez JIT. Piszesz:

while (myBean.getValue() > 1.0) {
  // perform some action
  Thread.sleep(1);
}

JIT kompiluje:

if (myBean.getValue() > 1.0) 
  while (true) {
    // perform some action
    Thread.sleep(1);
  }

W nieco odmiennych scenariuszach nawet kompilator Javy mógłby uzyskać podobny bajt (musiałby jedynie wyeliminować możliwość dynamicznego wysyłania do innego getValue). Jest to podręcznikowy przykład podnoszenia.

Dlaczego to jest legalne? Kompilator ma prawo zakładać, że wynik myBean.getValue() nie może się nigdy zmienić podczas wykonywania powyższy kod. Bez synchronized można ignorować wszelkie akcje innych wątków.
 13
Author: Marko Topolnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-12 20:12:08

Powodem jest ochrona przed jakimkolwiek innym wątkiem aktualizującym wartość podczas odczytu wątku, a tym samym unikanie wykonywania jakiejkolwiek akcji na starej wartości.

Tutaj metoda get uzyska wewnętrzną blokadę na " this "i dlatego każdy inny wątek, który może próbować ustawić/zaktualizować za pomocą metody setter, będzie musiał poczekać na uzyskanie blokady NA" this", aby wprowadzić metodę setter, która jest już uzyskana przez wątek wykonujący get.

Dlatego zaleca się przestrzeganie praktyki używania ta sama blokada podczas wykonywania dowolnej operacji na stanie zmiennym.

Sprawienie, że pole jest zmienne będzie działać tutaj, ponieważ nie ma złożonych instrukcji.


Ważne jest, aby pamiętać, że metody zsynchronizowane używają wewnętrznej blokady, która jest "this". Więc get I set oba są zsynchronizowane oznacza, że każdy wątek wprowadzający metodę będzie musiał uzyskać blokadę na tym.


Podczas wykonywania operacji nieatomowych 64-bitowych należy zwrócić szczególną uwagę. Fragmenty współbieżności Javy w Praktyka może być pomocna w zrozumieniu sytuacji -

"model pamięci Java wymaga, aby operacje pobierania i przechowywania były atomowe, ale dla nieulotnych długich i podwójnych zmiennych JVM może traktować 64-bitowy odczyt lub zapis jako dwa oddzielne 32 operacje bitowe. Jeśli odczyty i zapisy występują w różnych wątkach, możliwe jest zatem odczytanie nieulotnej długości i odzyskanie wysokich 32 bitów jednej wartości i niskich 32 bitów drugiej. Tak więc, nawet jeśli nie zależy ci na wartości czerstwe, to nie jest bezpieczne używanie współdzielonych zmiennych długich i podwójnych w programach wielowątkowych, chyba że zostaną zadeklarowane Lotny lub strzeżony przez zamek."

 1
Author: Upendra Upadhyay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-22 08:00:35

Może dla kogoś ten kod wygląda okropnie, ale działa bardzo dobrze.

  private Double value;
  public  void setValue(Double value){
    updateValue(value, true);
  }
  public Double getValue(){
      return updateValue(value, false);
  }
  private double updateValue(Double value,boolean set){
    synchronized(MyClass.class){
      if(set)
        this.value = value;
      return value;
    }
  }
 0
Author: Adam111p,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-10 19:57:10