2015-11-13 7 views
6

Na poniższym uproszczonym klasy:Java Widoczność Pamięci Konstruktorów

public class MutableInteger { 
    private int value; 
    public MutableInteger(int initial) { 
     synchronized(this) { // is this necessary for memory visibility? 
      this.value = initial; 
     } 
    } 
    public synchronized int get() { 
     return this.value; 
    } 
    public synchronized void increment() { 
     this.value++; 
    } 
    ... 
} 

Chyba ogólne pytanie jest dla zmiennych modyfikowalnych strzeżonych przez synchronizacji jest to niezbędne do synchronizacji przy ustalaniu wartości początkowej w konstruktorze?

+0

Co próbujesz osiągnąć? – biziclop

+1

Nie widzę żadnego sposobu, aby dwa wątki mogły być w tym samym wystąpieniu podczas jego konstruowania, więc powiedziałbym "nie". Jeśli wartość była prawdopodobnie statyczna, ale trzeba by zsynchronizować obiekt klasy, a nie ten odnośnik. – Pace

+1

@biziclop Próbuję tylko upewnić się, że mój kod jest poprawny w odniesieniu do bezpieczeństwa wątków i lepiej zrozumieć model pamięci Java. – nikdeapen

Odpowiedz

3

Masz rację, bez bloku synchronized w konstruktorze nie ma gwarancji widoczności dla pól nieostatecznych, jak można zobaczyć w this example.

Jednak w praktyce wolałbym używać pól volatile lub klas Atomic* w takich sytuacjach.

Aktualizacja: Ważne jest również, aby wspomnieć, że aby program się correctly synchronized (jak zdefiniowano przez JLS), trzeba będzie opublikować odniesienie do obiektu w sposób bezpieczny. Cytowany przykład tego nie robi, dlatego możesz zobaczyć niewłaściwą wartość w nieostatnich polach. Ale jeśli poprawnie opublikujesz odnośnik do obiektu (tj. Przypisując go do pola innego obiektu lub tworząc go przed wywołaniem Thread.start()), jest zagwarantowane, że twój obiekt będzie przynajmniej tak aktualny, jak czas publikowania, dzięki czemu blok synchronized w konstruktorze jest niepotrzebny.

+0

Dzięki, tego właśnie szukałem. Zdecydowanie użyłbym klas atomowych w tym przypadku, ale to działa tylko w prostych przypadkach. – nikdeapen

+0

Jeśli nie widziałem tego w specyfikacji Java na własne oczy, nazwałbym cię kłamcą. OK, czas na publikację o tym w Daily WTF. – Powerlord

+0

@Powerlord Uważam, że większość współczesnych maszyn wirtualnych tworzy barierę pamięci na końcu konstruktora, ale brak gwarancji rzeczywiście wygląda dziwnie. Jednak posiadanie jednej reguły dla konstruktora i innej dla innych zapisów byłoby prawdopodobnie jeszcze bardziej zagmatwane. – biziclop