W JCIP, sekcja 3.2.1 "Praktyki bezpiecznego konstruktora", istnieje ostrzeżenie przed wyciekaniem this
do innego wątku od konstruktora, "nawet jeśli publikacja jest ostatnią instrukcją w konstruktorze." Ta ostatnia część wydaje mi się zbyt silna i nie ma żadnego uzasadnienia. Co się dzieje po budowie, której muszę unikać? Czy są wyjątki? Interesuje mnie, ponieważ niedawno przesłałem kod, w którym zrobiłem to coś, i chcę zdecydować, czy istnieje uzasadnienie, aby wrócić i refactor.java: dlaczego nie powinno się uciec przed konstruktorem?
Odpowiedz
Jeśli chodzi o model pamięci Java, wyjście konstruktora odgrywa rolę w ostatecznej semantyce pola, dlatego istnieje różnica, czy instrukcja jest przed lub po zakończeniu konstruktora.
This works This doesn't work
-------------------------------------------------------------
static Foo shared; static Foo shared;
class Foo class Foo
{ {
final int i; final int i;
Foo() Foo()
{ {
i = 1; i = 1;
shared = this;
} }
} }
shared = new Foo(); new Foo();
(Uwaga: shared
nie jest lotna, publikacja jest przez rasy danych).
Jedyną różnicą między przykładami 2 przypisuje shared
przed lub po wyjściu konstruktora. W drugim przykładzie, i=1
może zostać zmieniony po przypisaniu.
Jeśli publikacja jest zsynchronizowaną czynnością, np. przez zmienną lotną, to jest ok; inne wątki będą obserwowały w pełni zainicjowany obiekt; pola nie muszą nawet mieć final
.
Publikacja za pośrednictwem wyścigu danych (lub robienia czegokolwiek przez wyścig danych) jest bardzo trudnym zadaniem, które wymaga bardzo ostrożnego uzasadnienia. Jeśli unikniesz wyścigu danych, sprawy są znacznie prostsze. Jeśli twój kod nie zawiera wyścigu danych, nie ma różnicy między wyciekiem this
bezpośrednio przed zakończeniem konstruktora, a publikowaniem go zaraz po zakończeniu konstruktora.
Nigdy nie należy przeciekać this
od konstruktora w jakimkolwiek punkcie, "nawet [...] w ostatnim zestawieniu." Ponieważ this
nie jest w pełni skonstruowany, mogą się zdarzyć bardzo dziwne rzeczy. Zobacz this SO answer na bardzo podobne pytanie.
Nigdy nie należy przechodzić this
z konstruktora (znanego jako „przecieka this
”)
Jednym z powodów, że nie powinno to zrobić, nawet jeśli jest to ostatni wiersz konstruktora, jest to, że JVM jest dozwolone do ponownego zamawiania wyciągów, o ile nie ma to wpływu na efekt w bieżącym wątku. Jeśli this
zostanie przekazany do procesu działającego w innym wątku, zmiana kolejności może spowodować dziwne i subtelne błędy.
Innym powodem jest to, że podklasy mogą zapewniać własną inicjalizację, więc konstrukcja może nie być kompletna na ostatnim wierszu konstruktora klasy.
- 1. Java - Metoda wykonana przed domyślnym konstruktorem
- 2. Inicjowanie zmiennej końcowej przed konstruktorem w Javie
- 3. Czego NIE powinno się testować?
- 4. Dlaczego inicjalizacja pól statycznych występuje przed konstruktorem statycznym?
- 5. Dlaczego powinno się unikać @@ class_variables w Ruby?
- 6. Dlaczego powinno być spacje po "[" i przed "]" w Bash?
- 7. Czego potrzebuję, aby uciec przed wysłaniem zapytania?
- 8. Wywołanie konstruktora klasy potomnej przed konstruktorem nadrzędnym
- 9. Jak mogę uciec przed ukośnikiem w vi?
- 10. Jak uciec przed gwiazdką w wyrażeniu regularnym?
- 11. Jak mogę uciec przed fragmentem kodu? (Vb.Net)
- 12. Jak uciec przed ukośnikiem w R?
- 13. webpack.optimize.ModuleConcatenationPlugin nie jest konstruktorem
- 14. Jak uciec przed szablonami ramek "@" w grze?
- 15. Java: dlaczego to się nie kompiluje?
- 16. fabric.Canvas nie jest konstruktorem
- 17. Dlaczego Node.js nie jest kompilowany przed uruchomieniem?
- 18. Jak zaprzyjaźnić się z konstruktorem klasy szablonowej?
- 19. Java Spring bean z prywatnym konstruktorem
- 20. Dlaczego to wyjście tekstu opisu "[Klasa] nie jest konstruktorem."?
- 21. Java. Runtime.getRuntime() exec() przekazuje argumenty Unicode kiedy nie powinno
- 22. swift: Nie można się komunikować z Konstruktorem interfejsu
- 23. htmlAtagi nie łączą się z konstruktorem tagów w moim rozszerzeniu
- 24. Dlaczego ustawić stan komponentu React poza konstruktorem?
- 25. wykrywanie kolizji nie powinno uczynić przedmiot teleportować się
- 26. Wykonanie konstruktora pochodnego przed konstruktorem bazowym w C#
- 27. TypeError: L.Control.Draw nie jest konstruktorem
- 28. Java: Regular Expression uciec Wyrażenie regularne
- 29. Prevent MongoDB przed śmiercią z „państwo powinno być: otwarte”
- 30. dlaczego java wnioskowanie nie
http://msmvps.com/blogs/jon_skeet/archive/2010/09/02/don-t-let-this-get-away.aspx – SLaks