2012-09-03 9 views
14

O ile wiem, że java.util.Date jest zmienna, więc nie jest wątek bezpieczne, jeśli wiele wątków próbowało uzyskać dostęp i modyfikowanie go. W jaki sposób wykorzystujemy blokowanie po stronie klienta lub kompozycję (opakowanie), aby zapewnić bezpieczeństwo wątków?Jak zrobić Java.util.Date wątku bezpieczny

+4

Jeśli już tu jesteśmy, 'GregorianCalendar' i' SimpleDateFormat' również nie są wątkami. Zawsze warto o tym pamiętać. –

+0

Dzięki za przypomnienie – peter

Odpowiedz

28

w tej kolejności od najlepszego do najgorszego:

  1. nie używać go w ogóle, sprawdź

  2. nie używać go w ogóle używać AtomicLong lub niezmienna prymitywny long z volatile do reprezentowania czas epoki

  3. Kapsuł go. Zawsze zwracaj kopię defensywną Date, nigdy nie odwołując się do obiektu wewnętrznego

  4. Wykonaj synchronizację na instancji .

+0

Zastanawiam się, dlaczego uważasz, że 2. jest lepszy od trzeciego? – peter

+2

@ user1389813: Dobre pytanie! 1. Prymitywy są niezmienne, a więc niejawnie wątkowo bezpieczne. 2. Nie można, przez przypadek, zwrócić odniesienia do obiektu wewnętrznego, a nie do kopii obronnej. 3. Więcej lekki, mniej kopiowania (naprawdę nie jest wielka sprawa). Jednak zgadzam się, że 2 i 3 są całkiem dobre. Również oczywiście "Date" ma lepszą semantykę niż "long". –

+0

Rozumiem. Drugi punkt, którego potrzebujesz, aby go chronić przy użyciu blokady? jak @dystroy wskazał, że operacja inkrementacji nie jest atomowa. – peter

-1

Nie ma prostego rozwiązania do tworzenia bezpiecznej dla wątków klasy Date. Najlepszym sposobem jest zsynchronizowanie wszystkich sposobów użycia obiektów za pomocą bloków synchronized.

+0

Następnie musisz nosić ten blok synchronizacji, gdziekolwiek go użyjesz. Czy nie jest to dobre w praktyce? – peter

+0

To okropne w kodzie. Dlatego odpowiedź Tomasza jest znacznie lepsza niż moja;) –

2

Najprostszym rozwiązaniem jest nigdy nie modyfikować daty i nigdy jej nie udostępniać. tj. używaj tylko daty dla zmiennych lokalnych.

Możesz używać JodaTime, ponieważ ma on niezmienne obiekty daty.

3

Możesz użyć wartości długiej (milisekund od epoki) zamiast instancji Date. Przypisanie jej będzie operacją atomową i zawsze będzie spójne.

Ale Twój problem może nie dotyczy samej wartości daty, ale całego algorytmu, co oznacza, że ​​prawdziwa odpowiedź byłaby oparta na twoim prawdziwym problemie.

Oto przykład działania buggy w wielowątkowego kontekstu:

long time; 
void add(long duration) { 
    time += duration; 
} 

Problemem jest to, że można mieć dwa dodatki równolegle wynikające tylko jeden skuteczny Ponadto, ponieważ time += duration nie jest atomowy (to naprawdę time=time+duration).

Używanie długiego zamiast zmiennego obiektu nie jest wystarczające. W takim przypadku można rozwiązać problem, ustawiając funkcję jako zsynchronizowaną, ale inne przypadki mogą być trudniejsze.

+0

Co masz na myśli mówiąc: "Twój problem może nie dotyczy samej wartości danych, ale całego algorytmu – peter

+0

Jeśli" rób ponownie długą operację rozpoczynając od odczytania daty i kończąc, zastępując wartość. Blokowanie wartości podczas operacji może to zrobić. –

+0

czy to pomoże, jeśli sprawi, że będzie niestabilny? – peter

Powiązane problemy