2012-01-14 13 views

Odpowiedz

21

Ponieważ jest ostateczny, tak. Zmienne końcowe mają specjalną semantykę związaną z bezpieczeństwem wątków, ponieważ inne wątki gwarantują, że końcowe pole znajdzie się przynajmniej w stanie, w którym znajdowało się, gdy zakończył się jego konstruktor.

To jest w JLS 17.5, choć język jest nieco gęsty. Te semantyki zostały wprowadzone w Javie 1.5, w szczególności przez JSR-133. Zobacz tę stronę dla niespecjalistycznej dyskusji na temat JSR-133 i jego różnych implikacji.

Zauważ, że jeśli zmodyfikować instancji po jej konstruktora, czyli nie koniecznie wątku bezpieczne. W takim przypadku należy podjąć zwykłe środki bezpieczeństwa dotyczące nici, aby zapewnić, że zdarzy się to przed wcześniejszymi krawędziami.

Jestem dość pewny (choć nie całkiem w 100%), że fakt, że tylko jeden wątek inicjuje klasę, to , a nie czynnik tutaj. To prawda, że ​​klasa jest inicjowana tylko przez jeden wątek, ale nie wierzę, że są jakieś konkretne zdarzenia - zanim krawędzie zostały ustanowione między tymi wątkami jakikolwiek inny wątek, który używa klasy (inny niż ten inny wątek bez konieczności ponownego inicjowania klasa). Tak więc bez słowa kluczowego final inny wątek byłby w stanie zobaczyć częściowo skonstruowaną instancję obiektu. Zdarzają się określone przedtem krawędzie zdefiniowane przez JMM: JLS 17.4.5, a inicjowanie klasy nie jest tam wymienione.

+0

tak, dziękuję. Świetna odpowiedź – MyTitle

+0

Uważam, że ważniejszym powodem niż końcowym jest to, że inicjalizacja klasy (inicjalizacja statyczna) musi być zsynchronizowana i bezpieczna dla wątków. Wykorzystując synchronizację, ustalamy, co dzieje się przed złożeniem zamówienia. Więcej szczegółów znajduje się w 12.4.2 (http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2). – sjlee

+0

@ sjlee To prawda, że ​​inicjalizacja wymaga blokad, ale jeśli wątek A inicjalizuje MyClass, a wątek B pojawia się około 5 minut później i używa MyClass, wątek B nie będzie próbował zainicjować MyClass (ponieważ został już zainicjowany). Oznacza to, że nie uzyska blokady na 'MyClass.class', co oznacza, że ​​nie ma żadnego związku pomiędzy działaniami wątku A a wątkiem B. Gdyby każdy wątek blokował 'MyThread.class' kiedykolwiek go używał, nigdy nie musiałbyś nawiązywać żadnych innych kontaktów. – yshavit

2

Statyczny blok inicjalizacyjny dowolnej klasy ma zagwarantowany pojedynczy gwint. Prostszym singletonem jest użycie enum Jest to również bezpieczne dla wątków i zainicjowane w klasie.

+0

Odsyłacz do tego, np. JLS? – paislee

+0

@paislee: Jestem bardziej jak u siebie w JVMS, więc mogę ci podać [odniesienie do tego] (http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc. html # 24237). Jeśli postępujesz zgodnie z procedurą, zobaczysz, że inicjowanie klasy może być wykonywane tylko przez pojedynczy wątek (dla każdego programu ładującego klasy). Statyczny inicjator jest wywoływany w kroku 8. – musiKk

+1

JVMS zapewnia surowszą semantykę niż JLS na różne sposoby, więc nie jest doskonałym źródłem ogólnej poprawności językowej. JLS definiuje inicjowanie klasy w [JLS 12.4] (http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4), a 12.4.2 szczegółowo opisuje procedurę. – yshavit

3

Gwarantuje to bezpieczeństwo wątków, ponieważ JVM gwarantuje, że inicjatory statyczne są wykonywane na pojedynczym wątku.

Nie oznacza to, że instancja Foo jest wewnętrznie bezpieczna - oznacza to tylko, że masz zagwarantowane, że konstruktor Foo zostanie wywołany dokładnie raz, w jednym wątku, przez tę konkretną ścieżkę kodu.

5

konstruktorów klasy i statyczne/instance inicjalizatory zagwarantowane mają być wykonywane atomowo i od private static final FOO INSTANCE = new FOO; jest równoważna

private static final FOO INSTANCE; 

static{ 
    INSTANCE = new FOO(); 
} 

sprawa ta mieści się w powyższej kategorii.

Powiązane problemy