2017-04-27 14 views
10

Patrząc na klasę Java String możemy zobaczyć, że kod mieszania jest buforowany po pierwszej ocenie.java string mechanizm buforowania hashcode

public int hashCode() { 
    int h = hash; 
    if (h == 0 && value.length > 0) { 
     char val[] = value; 

     for (int i = 0; i < value.length; i++) { 
      h = 31 * h + val[i]; 
     } 
     hash = h; 
    } 
    return h; 
} 

Gdzie hash jest zmienną instancji. Mam pytanie, dlaczego potrzebujemy dodatkowej zmiennej?

+1

Jest napisany w ten sposób, aby zapewnić, że klasa 'String' jest wątkowo bezpieczna. Możesz przeczytać więcej o tej koncepcji [tutaj] (https://en.wikipedia.org/wiki/Thread_safety) – Valy

+1

Ten link do Wikipedii nie wyjaśnia w pełni, co tu się dzieje i dlaczego. –

Odpowiedz

5

Po prostu ponieważ wartość hash zmienia się w pętli, a rozwiązanie bez pośredniej zmiennej tymczasowej nie jest bezpieczne dla wątków. Załóżmy, że ta metoda jest wywoływana w kilku wątkach.

Powiedzmy, że thread-1 Rozpoczęto obliczenia hash i nie jest to już 0. Jakiś mały czas później thread-2 wywołuje tę samą metodę na tym samym obiekcie, co hashCode() i widzi, że hash nie jest 0, ale thread-1 jeszcze nie zakończył obliczeń. W rezultacie w wartości thread-2 zostanie użyta błędna wartość hash (nie w pełni obliczona).

3

Jest to prosty i tani mechanizm synchronizacji.

Jeśli wątek wywoła funkcję hashCode() po raz pierwszy, a drugi wątek wywoła go ponownie, podczas gdy pierwszy wątek oblicza skrót, drugi wątek zwróci nieprawidłowy hasz (wartość pośrednia obliczenia w pierwszym wątku) jeśli używasz bezpośrednio atrybutu.

+1

Należy pamiętać, że zabezpieczenie wątków nie zapobiega obliczeniu wartości skrótu przez więcej niż jeden wątek. Ponieważ nie ma mechanizmu synchronizacji, nie ma gwarancji, że a) dwa wątki nie będą miały dostępu do 'hash', dopóki jest to' 0', ani b), że nawet po tym, jak jeden wątek buforuje, że każdy inny wątek zobaczy wynik. Dlaczego jest bezpieczny w wątku, mimo że może być obliczany wiele razy? Ponieważ obliczenia są idempotentne; żadne dwa wątki nie mogą obliczyć różnych wartości. –

+2

Zupełnie w prawo, Lew. W takim przypadku obliczenie dwukrotnie wartości skrótu ma niewielki wpływ na początku w porównaniu z korzyścią, która nie wymaga żadnego mechanizmu synchronizacji podczas okresu istnienia łańcucha. – Mario

1

Mówiąc prościej: lokalny prymitywny h jest dobrze lokalny; w ten sposób bezpieczny dla wątków; w przeciwieństwie do hash, która jest wspólna.