Czy niezsynchronizowane metody statyczne są bezpieczne wątkowo, jeśli nie modyfikują statycznych zmiennych klas?

145

Zastanawiałem się, czy masz metodę statyczną, która nie jest zsynchronizowana, ale nie modyfikuje żadnych zmiennych statycznych, czy jest bezpieczna wątkowo? A co jeśli metoda tworzy w niej zmienne lokalne? Na przykład, czy poniższy kod jest bezpieczny dla wątków?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Więc jeśli mam dwa wątki wzywające tę metodę w sposób ciągły i równoczesny, jeden z psami (powiedz „dog niemiecki” i „pies byk”), a drugi z kotami (powiedz „perski” i „syjamski”), czy kiedykolwiek dostanę koty i psy w tej samej tablicy? A może koty i psy nigdy nie będą znajdować się w tym samym inwokacji metody w tym samym czasie?

Sanki
źródło
inny wątek na ten temat: stackoverflow.com/questions/8015797/…
象 嘉 道
2
To inna kwestia, czy wywołanie metody statycznej jest bezpieczne wątkowo, a nie, czy tablice są.
Sanki

Odpowiedzi:

212

Ta metoda jest w 100% bezpieczna dla wątków, nawet gdyby nie była static. Problem z bezpieczeństwem wątków pojawia się, gdy musisz udostępniać dane między wątkami - musisz zadbać o atomowość, widoczność itp.

Ta metoda działa tylko na parametrach, które znajdują się na stosie i odwołaniach do niezmiennych obiektów na stercie. Stos jest z natury lokalny dla wątku , więc nigdy nie następuje udostępnianie danych.

Niezmienne obiekty ( Stringw tym przypadku) są również bezpieczne dla wątków, ponieważ po utworzeniu nie można ich zmienić, a wszystkie wątki mają tę samą wartość. Z drugiej strony, gdyby metoda akceptowała (zmienna) Date, mógłbyś mieć problem. Dwa wątki mogą jednocześnie modyfikować tę samą instancję obiektu, powodując warunki wyścigu i problemy z widocznością.

Tomasz Nurkiewicz
źródło
4
Poprawna odpowiedź. Zmienne poziomu metody są replikowane w każdym stosie wykonywania wątków.
Sid
z technicznego punktu widzenia metoda ma być wstawiona, a parametrami będą rejestry procesora. Niemniej jednak odpowiedź jest prawidłowa
najlepsze wyniki
43
Stos jest oczywiście lokalny dla bieżącego wątku, ale możesz mieć odniesienia do obiektów współdzielonych na tym stosie. Nie jest to problem w przykładzie, ponieważ ciągi są niezmienne, ale metoda modyfikująca przekazany parametr może mieć problemy z bezpieczeństwem wątków, jeśli ten przekazany obiekt jest dostępny z wielu wątków.
Jörn Horstmann
1
Jak wspomniał @TomaszNurkiewicz, jeśli przekażemy zmienne odniesienie do obiektu, możemy dostać się do warunków wyścigu. Czy to prawda, nawet jeśli metoda w żaden sposób nie zmienia obiektu? Mam na myśli, czy nadal będzie to klasyfikowane jako stan wyścigu, ponieważ obiekt był zmienny? A co jeśli dodamy ostatnie słowo kluczowe do parametrów?
Rafay
Co się stanie, jeśli przekażę obiekt klasy w metodzie? Czy zmienna będzie w stosie lub stercie?
grep
28

Metoda może być niebezpieczna dla wątków tylko wtedy, gdy zmienia stan udostępnienia. Nie ma znaczenia, czy jest statyczny, czy nie.

Konrad Garus
źródło
3
@Konrad_Garus Pytanie dotyczyło tego, czy zmienne lokalne stanowią stan współdzielony, czy też nie, lub czy stos dla metody statycznej jest na wątek lub współdzielony.
Sanki
„Metoda może być niebezpieczna dla wątków tylko wtedy, gdy zmienia stan współużytkowania”. Nie, może być również niebezpieczny dla wątku, jeśli tylko uzyskuje dostęp do udostępnionego stanu bez zmiany go. Niezsynchronizowany dostęp do modyfikowalnego obiektu może uzyskać dostęp do niespójnego stanu, jeśli obiekt jest mutowany przez inny wątek, nawet jeśli drugi wątek jest prawidłowo zsynchronizowany. Oba wątki wymagają odpowiedniej synchronizacji, aby zachować bezpieczeństwo wątków.
Warren Dew
12

Ta funkcja jest całkowicie bezpieczna dla wątków.

Jeśli się nad tym zastanowić ... załóżmy, co by się stało, gdyby było inaczej. Każda zwykła funkcja miałaby problemy z wątkami, gdyby nie była zsynchronizowana, więc wszystkie funkcje API w JDK musiałyby być zsynchronizowane, ponieważ potencjalnie mogłyby być wywoływane przez wiele wątków. A ponieważ przez większość czasu aplikacja korzysta z jakiegoś interfejsu API, aplikacje wielowątkowe byłyby praktycznie niemożliwe.

To zbyt śmieszne, aby o tym myśleć, więc tylko dla Ciebie: metody nie są bezpieczne dla wątków, jeśli istnieje wyraźny powód, dla którego mogą wystąpić problemy. Staraj się zawsze myśleć o tym, co by było, gdyby w mojej funkcji było wiele wątków, a co, gdybyś miał debuger krokowy i krok po kroku przesuwał pierwszy ... potem drugi wątek ... może znowu drugi ... czy byłyby problemy? Jeśli znajdziesz, nie jest bezpieczny wątkowo.

Należy również pamiętać, że większość klas Java 1.5 Collection nie jest bezpieczna wątkowo, z wyjątkiem tych, w których jest to określone, takich jak ConcurrentHashMap.

A jeśli naprawdę chcesz się w to zagłębić, przyjrzyj się uważnie słowu kluczowemu „volatile” i WSZYSTKIM jego skutkom ubocznym. Przyjrzyj się klasom Semaphore () i Lock () oraz ich przyjaciołom w java.util.Concurrent. Przeczytaj całą dokumentację API dotyczącą klas. Warto się uczyć i satysfakcjonować.

Przepraszam za tę zbyt rozbudowaną odpowiedź.

Daniel
źródło
2
„Jeśli się nad tym zastanowić… załóżmy, co by się stało, gdyby było inaczej. Każda zwykła funkcja miałaby problemy z wątkami, gdyby nie była zsynchronizowana, więc wszystkie funkcje API w JDK musiałyby być zsynchronizowane, ponieważ potencjalnie mogłyby być wywoływane przez wiele wątków ”. Słuszna uwaga!
Sanki
1

Użyj staticsłowa kluczowego ze zsynchronizowanymi metodami statycznymi, aby zmodyfikować dane statyczne współdzielone między wątkami. Za pomocą staticsłowa kluczowego wszystkie utworzone wątki będą walczyć o jedną wersję metody.

Użycie volatilesłowa kluczowego wraz z metodami zsynchronizowanych wystąpień zagwarantuje, że każdy wątek będzie miał własną kopię udostępnionych danych i żadne operacje odczytu / zapisu nie będą wyciekać między wątkami.

Clinton
źródło
0

Niezmienne obiekty ciągów to kolejny powód powyższego scenariusza bezpiecznego dla wątków. Zamiast tego, jeśli używane są zmienne obiekty (powiedzmy makeMutableArray ..), z pewnością zostanie przerwane bezpieczeństwo wątków.

szorstki
źródło
Pytanie brzmiało, czy wywołanie metody statycznej kiedykolwiek zobaczyłoby argumenty innego wywołania tej samej metody z innego wątku. Odpowiedź brzmi: „nie!”. Wiedziałem o tym, ale chciałem móc to udowodnić wątpliwym współpracownikom.
Sled
Dlaczego ta odpowiedź została przegłosowana? Chodzi o to, czego nie wnoszą inne odpowiedzi, a zmienność może mieć charakter wewnętrzny lub zewnętrzny. Jeśli zwrócisz zmienną, nie jesteś bezpieczny dla wątków. Pytanie nie stawia pytania tak wąsko, jak sugeruje komentarz; rozszerzone pytanie po próbce kodu mogło zostać wyrażone w kodzie, być może jako test jednostkowy. Ale sympatyzuję z próbami przekonania współpracowników. „Nie wierzą mi, mojemu kodowi testowemu ani Joshowi Blochowi, ale może zaakceptują odpowiedź na SO”.
som-snytt