Wszyscy ostrzegają, że Java DateFormat nie jest bezpieczna dla wątków i rozumiem tę koncepcję teoretycznie.
Ale nie jestem w stanie wyobrazić sobie, jakie faktyczne problemy możemy napotkać z tego powodu. Powiedzmy, że mam pole DateFormat w klasie i to samo jest używane w różnych metodach w klasie (formatowanie dat) w środowisku wielowątkowym.
Czy to spowoduje:
- każdy wyjątek, taki jak wyjątek formatu
- rozbieżność danych
- jakikolwiek inny problem?
Proszę również wyjaśnić dlaczego.
java
multithreading
date-format
haps10
źródło
źródło
Odpowiedzi:
Wypróbujmy to.
Oto program, w którym wiele wątków używa udostępnionego pliku
SimpleDateFormat
.Program :
Uruchom to kilka razy, a zobaczysz:
Wyjątki :
Oto kilka przykładów:
1.
2.
3.
Nieprawidłowe wyniki :
Prawidłowe wyniki :
Innym podejściem do bezpiecznego używania DateFormats w środowisku wielowątkowym jest użycie
ThreadLocal
zmiennej do przechowywaniaDateFormat
obiektu, co oznacza, że każdy wątek będzie miał swoją własną kopię i nie będzie musiał czekać, aż inne wątki go zwolnią. Oto jak:Oto dobry post z większą liczbą szczegółów.
źródło
Spodziewałbym się uszkodzenia danych - np. Jeśli analizujesz dwie daty w tym samym czasie, możesz mieć jedno połączenie zanieczyszczone danymi z innego.
Łatwo sobie wyobrazić, jak to się może stać: analizowanie często wymaga zachowania określonego stanu tego, co przeczytałeś do tej pory. Jeśli dwa wątki depczą w tym samym stanie, pojawią się problemy. Na przykład
DateFormat
ujawniacalendar
pole typuCalendar
i patrząc na kodSimpleDateFormat
, wywołanie niektórych metodcalendar.set(...)
i wywołanie innychcalendar.get(...)
. To oczywiście nie jest bezpieczne dla wątków.Nie spojrzał w dokładnych szczegółach dlaczego
DateFormat
nie jest bezpieczny wątku, ale dla mnie to wystarczy, aby wiedzieć, że to jest niebezpieczne bez synchronizacji - dokładne sposoby braku bezpieczeństwa mogą się nawet zmieniać między wydaniami.Osobiście użyłbym zamiast tego parserów z Joda Time , ponieważ są one bezpieczne dla wątków - a Joda Time jest znacznie lepszym API daty i czasu na początek :)
źródło
Jeśli używasz Java 8, możesz użyć
DateTimeFormatter
.Kod:
Wynik:
źródło
Mówiąc ogólnie, nie należy definiować
DateFormat
zmiennej jako wystąpienia obiektu, do którego ma dostęp wiele wątków, lubstatic
.Tak więc, na wypadek,
Foo.handleBar(..)
gdybyś miał dostęp do wielu wątków, zamiast:powinieneś użyć:
Ponadto we wszystkich przypadkach nie należy mieć rozszerzenia
static
DateFormat
Jak zauważył Jon Skeet, możesz mieć zarówno statyczne, jak i współdzielone zmienne instancji w przypadku wykonywania zewnętrznej synchronizacji (tj. Używania
synchronized
wokół wywołańDateFormat
)źródło
SimpleDateFormat
bardzo często. Będzie to zależeć od wzorca użytkowania.Oznacza to, że załóżmy, że masz obiekt DateFormat i uzyskujesz dostęp do tego samego obiektu z dwóch różnych wątków i wywołujesz metodę formatowania na tym obiekcie oba wątki wejdą w tę samą metodę w tym samym czasie na tym samym obiekcie, abyś mógł zwizualizować, że wygrał nie daje właściwego wyniku
Jeśli musisz w jakikolwiek sposób pracować z DateFormatem, powinieneś coś zrobić
źródło
Dane są uszkodzone. Wczoraj zauważyłem to w moim programie wielowątkowym, w którym miałem
DateFormat
obiekt statyczny i wywołałem jegoformat()
wartości odczytywane przez JDBC. Miałem instrukcję wyboru SQL, w której przeczytałem tę samą datę z różnymi nazwami (SELECT date_from, date_from AS date_from1 ...
). Takie stwierdzenia były używane w 5 wątkach dla różnych dat wWHERE
clasue. Daty wyglądały „normalnie”, ale różniły się wartością - podczas gdy wszystkie daty pochodziły z tego samego roku, tylko miesiąc i dzień ulegały zmianie.Inne odpowiedzi pokazują, jak uniknąć takiej korupcji. Zrobiłem moje
DateFormat
nie statyczne, teraz jest członkiem klasy, która wywołuje instrukcje SQL. Testowałem również wersję statyczną z synchronizacją. Oba działały dobrze, bez różnicy w wydajności.źródło
Specyfikacje Format, NumberFormat, DateFormat, MessageFormat itp. Nie zostały zaprojektowane tak, aby były bezpieczne dla wątków. Ponadto metoda parse wywołuje
Calendar.clone()
metodę i wpływa na ślady kalendarza, więc wiele wątków analizowanych jednocześnie zmieni klonowanie wystąpienia Calendar.Co więcej, są to raporty o błędach, takie jak ten i ten , z wynikami problemu z bezpieczeństwem wątków DateFormat.
źródło
W najlepszej odpowiedzi dogbane podał przykład użycia
parse
funkcji i do czego prowadzi. Poniżej znajduje się kod, który pozwala sprawdzićformat
działanie.Zauważ, że jeśli zmienisz liczbę executorów (współbieżnych wątków), otrzymasz inne wyniki. Z moich eksperymentów:
newFixedThreadPool
wartość 5, a pętla za każdym razem zawiedzie.Zgaduję, że YMMV w zależności od twojego procesora.
format
Funkcja nie przez czas formatowania z innym wątku. Dzieje się tak, ponieważformat
funkcja wewnętrznie używacalendar
obiektu, który jest ustawiony na początkuformat
funkcji. Acalendar
obiekt jest własnościąSimpleDateFormat
klasy. Westchnienie...źródło
Jeśli istnieje wiele wątków manipulujących / uzyskujących dostęp do pojedynczej instancji DateFormat i synchronizacja nie jest używana, można uzyskać zaszyfrowane wyniki. Dzieje się tak, ponieważ wiele operacji nieatomowych może zmieniać stan lub widzieć pamięć niespójnie.
źródło
To jest mój prosty kod, który pokazuje, że DateFormat nie jest bezpieczny dla wątków.
Ponieważ wszystkie wątki używają tego samego obiektu SimpleDateFormat, zgłasza następujący wyjątek.
Ale jeśli przekażemy różne obiekty do różnych wątków, kod działa bez błędów.
Takie są wyniki.
źródło
To spowoduje
ArrayIndexOutOfBoundsException
Oprócz nieprawidłowego wyniku, od czasu do czasu będzie się to zawieszać. To zależy od prędkości twojej maszyny; w moim laptopie zdarza się to średnio raz na 100 000 połączeń:
ostatnia linia może wywołać opóźniony wyjątek executora:
źródło