Zachowanie metody statycznej w środowisku wielowątkowym w Javie

114

Jest proste, głupie pytanie, które przeszkadza mi i rodzi kilka argumentów w mojej głowie. Chcę odrzucić wszystkie wątpliwości dotyczące poniższych pytań.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

Załóżmy, że każdy z pięciu wątków wykonuje wywołanie Clstest.testStaticMethod("arg-n")w tym samym czasie.

Wątek 1 wywołuje Clstest.testStaticMethod("arg-1").

Gdy wątek 1 znajduje się w sekcji 1, wywołuje wątek 2 Clstest.testStaticMethod("arg-2").

Co się stanie z wątkiem 1? Czy przejdzie w stan uśpienia?

Kiedy wątek 1 dostanie szansę, czy wznowi wykonywanie od sekcji 1, w której został wstrzymany?

Jak to się dzieje, gdy we wszystkich pięciu wątkach jest jeden Clstest.testStaticMethodi Clstest.testStaticMethodto samo ?

Czy istnieje możliwość zamiany inFileStrwysłanych wieloma wątkami?

namalfernandolk
źródło
Na jaki język kierujesz reklamy?
ΩmegaMan
3
@ OmegaMan: to java
namalfernandolk

Odpowiedzi:

192

Odpowiedź Hansa Passanta jest dobra. Ale pomyślałem, że spróbuję wyjaśnić na nieco prostszym poziomie każdemu, kto zetknie się z tym i jest nowicjuszem w Javie. Tutaj idzie..

Pamięć w Javie jest podzielona na dwa rodzaje - stertę i stosy. Sterta to miejsce, w którym żyją wszystkie obiekty, a stosy są tam, gdzie nici wykonują swoją pracę. Każdy wątek ma swój własny stos i nie ma dostępu do innych stosów. Każdy wątek ma również wskaźnik do kodu, który wskazuje na bit kodu, który aktualnie działa.

Gdy wątek rozpoczyna uruchamianie nowej metody, zapisuje argumenty i zmienne lokalne tej metody na swoim własnym stosie. Niektóre z tych wartości mogą wskazywać na obiekty na stercie. Jeśli dwa wątki uruchomią tę samą metodę w tym samym czasie, oba będą miały swoje wskaźniki kodu wskazujące na tę metodę i będą miały własne kopie argumentów i zmiennych lokalnych na swoich stosach. Będą kolidować ze sobą tylko wtedy, gdy rzeczy na ich stosach będą wskazywać te same obiekty na stercie. W takim przypadku mogą się zdarzyć różne rzeczy. Ale jak wskazuje Hans, ciągi znaków są niezmienne (nie można ich zmienić), więc jesteśmy bezpieczni, jeśli jest to jedyny obiekt, który jest „udostępniany”.

Tak wiele wątków może działać tą samą metodą. Mogą nie działać w tym samym czasie - zależy to od liczby rdzeni na komputerze, ponieważ JVM odwzorowuje wątki Java na wątki systemu operacyjnego, które są zaplanowane na wątki sprzętowe. W związku z tym masz niewielką kontrolę nad sposobem przeplatania się tych wątków bez stosowania skomplikowanych mechanizmów synchronizacji .

Zauważ, że spanie jest czymś, co robi sobie nić.

selig
źródło
3
Tak więc w środowisku wielordzeniowych procesorów może być wiele wątków działających w tym samym czasie, prawda? W środowisku z jednym procesorem w danym momencie działa tylko jeden wątek. (wiele wątków dzieli czas między sobą). Więc kiedy harmonogram wątku daje szansę z bieżącego wątku (A) do wątku (B), w jaki sposób wątek (A) jest wznawiany od miejsca, w którym został wstrzymany? Mam na myśli, skąd zna punkt wznowienia? Czy to dlatego, że „każdy wątek ma również wskaźnik do kodu, który wskazuje na bit kodu, który aktualnie działa?” jak powiedziałeś?
namalfernandolk
6
Masz to. Żeby wyjaśnić kilka kwestii - po pierwsze, sposób planowania wątków jest poza kontrolą Javy. Mówię tutaj o JVM Hotspot firmy Sun. JVM mapuje wątek Java na wątek systemu operacyjnego, a system operacyjny decyduje, które wątki mają zostać uruchomione. Jak powiedziałeś, na jednym rdzeniu system operacyjny może działać tylko jeden naraz, ale na komputerze wielordzeniowym może działać więcej niż jeden naraz. Po drugie, wątek nie jest tak naprawdę świadomy tego, kiedy zostaje wstrzymany, jedyne informacje, które ma, to wskaźnik programu (wskaźnik do kodu) i stos, które są zapisywane i przywracane dokładnie tak, jak były.
selig
Tak więc interferencja między wątkami ma miejsce, gdy wątki używają zmiennych spoza ich lokalnego zakresu i na przykład jeden wątek aktualizuje wartość zmiennej, zanim inny wątek pobierze tę zmienną (lub wskaźnik do zmiennej) na swoim własnym stosie? Czy to właściwe zrozumienie?
hariszhr
2
Aby być nieco bardziej precyzyjnym ... interferencja może się zdarzyć i może się zdarzyć, ale niekoniecznie nastąpi ... gdy wątki współdzielą rzeczy na stercie (nielokalne). Istnieje kilka różnych sposobów, w jakie mogą wystąpić zakłócenia, które zależą od zależności między różnymi częściami kodu. Nie jestem pewien co do twojego przykładu, ponieważ brakuje niektórych szczegółów. Być może odnosisz się do potencjalnego problemu, w którym wątki A i B odczytują wspólną wartość, a następnie aktualizują ją na podstawie odczytanej wartości. To wyścig danych.
selig
1
@selig, jeśli mam klasę z metodami instancji tylko dla ex: klasa usług i jest to pojedyncza, nie muszę się martwić o wiele wątków wykonujących metody instancji naraz, ponieważ klasa usługi nie ma żadnego stanu, w którym stan występuje tylko wtedy, gdy klasa ma zmienne instancji. Czy moje rozumienie jest prawidłowe?
Yug Singh
67

Czy przejdzie w stan uśpienia?

Nie, uruchomienie wątku nie wpływa na inne wątki, o ile nie są one celowo synchronizowane ze sobą. Jeśli masz więcej niż jeden rdzeń procesora, tak jak wszystkie najnowsze maszyny, te wątki prawdopodobnie będą wykonywane dokładnie w tym samym czasie. Staje się to nieco mniej prawdopodobne, gdy uruchomisz 5 wątków, ponieważ twój komputer może nie mieć wystarczającej liczby rdzeni. System operacyjny jest zmuszony wybierać między nimi, dając każdemu trochę czasu na uruchomienie. Zadanie harmonogramu wątków. Wątek nie będzie wtedy w stanie „uśpienia”, jest po prostu wstrzymywany i czeka, aż program planujący wątki da mu szansę na uruchomienie. Zostanie wznowiony w miejscu, w którym został przerwany przez harmonogram.

Czy istnieje możliwość zamiany inFileStr wysyłanych przez wiele wątków?

Nie ma takiej możliwości, wątki mają swój własny stos, więc każdy argument metody i zmienna lokalna będą unikalne dla każdego wątku. Użycie łańcucha gwarantuje ponadto, że te wątki nie mogą ze sobą kolidować, ponieważ łańcuchy są niezmienne.

Nie ma takiej gwarancji, jeśli argument jest odwołaniem do innego rodzaju zmiennego obiektu. Lub jeśli sama metoda używa zmiennych statycznych lub odwołań do obiektów na stercie. Synchronizacja jest wymagana, gdy wątek modyfikuje obiekt, a inny wątek go odczytuje. Blokady słów kluczowych w języku C # jest droga boilerplate wdrożyć taki wymaganej synchronizacji. Fakt, że metoda jest statyczna , nie oznacza, że ​​taka synchronizacja nigdy nie jest wymagana. Jest tylko mniej prawdopodobne, ponieważ nie musisz martwić się o wątki uzyskujące dostęp do tego samego obiektu (udostępniając go ).

Hans Passant
źródło
3
Ups, nigdy nie widziałem tagu [java]. Wystarczająco blisko.
Hans Passant
Zapomniałem dodać, kiedy został opublikowany. Mój błąd. :). W każdym razie dziękuję za odpowiedź. To było bardzo pomocne.
namalfernandolk