java synchronized what is thread synchronization java
Ten samouczek wyjaśnia synchronizację wątków w Javie wraz z pokrewnymi pojęciami, takimi jak Java Lock, Race Condition, Mutex, Java Volatile i Deadlock w Javie:
W środowisku wielowątkowym, w którym zaangażowanych jest wiele wątków, zdarzają się konflikty, gdy więcej niż jeden wątek próbuje uzyskać ten sam zasób w tym samym czasie. Te starcia skutkują „stanem wyścigu”, a zatem program daje nieoczekiwane rezultaty.
Na przykład, pojedynczy plik jest aktualizowany przez dwa wątki. Jeśli jeden wątek T1 jest w trakcie aktualizacji tego pliku, powiedz jakąś zmienną. Teraz, gdy aktualizacja przez T1 jest nadal w toku, powiedzmy, że drugi wątek T2 również aktualizuje tę samą zmienną. W ten sposób zmienna da błędne wyniki.
=> Obejrzyj całą serię szkoleń dotyczących języka Java.
Gdy zaangażowanych jest wiele wątków, powinniśmy zarządzać tymi wątkami w taki sposób, aby w danej chwili dostęp do zasobu był możliwy przez jeden wątek. W powyższym przykładzie plik, do którego mają dostęp oba wątki, powinien być zarządzany w taki sposób, aby T2 nie mógł uzyskać dostępu do pliku, dopóki T1 nie uzyska do niego dostępu.
Odbywa się to w Javie za pomocą „ Synchronizacja wątków ”.
Czego się nauczysz:
- Synchronizacja wątków w Javie
- Wielowątkowość bez synchronizacji
- Wielowątkowość z synchronizacją
- Wniosek
Synchronizacja wątków w Javie
Ponieważ Java jest językiem wielowątkowym, synchronizacja wątków ma duże znaczenie w Javie, ponieważ wiele wątków jest wykonywanych równolegle w aplikacji.
Używamy słów kluczowych „Zsynchronizowany” i 'lotny' aby osiągnąć synchronizację w Javie
Potrzebujemy synchronizacji, gdy współdzielony obiekt lub zasób jest zmienny. Jeśli zasób jest niezmienny, wątki będą odczytywać zasób tylko współbieżnie lub indywidualnie.
W takim przypadku nie musimy synchronizować zasobu. W takim przypadku JVM zapewnia to Zsynchronizowany kod Java jest wykonywany w jednym wątku na raz .
W większości przypadków równoczesny dostęp do współdzielonych zasobów w Javie może powodować błędy, takie jak „niespójność pamięci” i „interferencja wątków”. Aby uniknąć tych błędów, musimy przejść do synchronizacji współdzielonych zasobów, aby dostęp do tych zasobów wzajemnie się wykluczał.
Używamy koncepcji zwanej Monitory do realizacji synchronizacji. W danym momencie dostęp do monitora jest możliwy tylko przez jeden wątek. Kiedy wątek zostanie zablokowany, możemy powiedzieć, że wszedł do monitora.
Gdy dostęp do monitora jest uzyskiwany przez określony wątek, monitor jest blokowany, a wszystkie inne wątki próbujące wejść do monitora są zawieszane do czasu zakończenia wątku uzyskującego dostęp i zwolnienia blokady.
Idąc dalej, szczegółowo omówimy synchronizację w Javie w tym samouczku. Omówmy teraz kilka podstawowych pojęć związanych z synchronizacją w Javie.
Stan wyścigu w Javie
W środowisku wielowątkowym, gdy więcej niż jeden wątek próbuje uzyskać dostęp do udostępnionego zasobu w celu zapisu jednocześnie, wiele wątków ściga się ze sobą, aby zakończyć uzyskiwanie dostępu do zasobu. Prowadzi to do „wyścigu”.
Należy wziąć pod uwagę, że nie ma problemu, jeśli wiele wątków próbuje uzyskać dostęp do udostępnionego zasobu tylko w celu odczytu. Problem pojawia się, gdy wiele wątków uzyskuje dostęp do tego samego zasobu w tym samym czasie.
Warunki wyścigu wynikają z braku odpowiedniej synchronizacji wątków w programie. Kiedy prawidłowo zsynchronizujemy wątki, tak że w danej chwili tylko jeden wątek będzie miał dostęp do zasobu, a stan wyścigu przestanie istnieć.
Jak więc możemy wykryć stan wyścigu?
Najlepszym sposobem na wykrycie sytuacji wyścigu jest przegląd kodu. Jako programista powinniśmy dokładnie przejrzeć kod, aby sprawdzić potencjalne warunki wyścigu, które mogą wystąpić.
Blokady / monitory w Javie
Wspomnieliśmy już, że do realizacji synchronizacji używamy monitorów lub blokad. Monitor lub blokada jest jednostką wewnętrzną i jest powiązana z każdym obiektem. Tak więc zawsze, gdy wątek musi uzyskać dostęp do obiektu, musi najpierw uzyskać blokadę lub monitor swojego obiektu, popracować nad obiektem, a następnie zwolnić blokadę.
Blokady w Javie będą wyglądać tak, jak pokazano poniżej:
public class Lock { private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while(isLocked) { wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
Jak pokazano powyżej, mamy metodę lock (), która blokuje instancję. Wszystkie wątki wywołujące metodę lock () będą blokowane, dopóki zestawy metod unblock () nie zostaną oznaczone flagą Locked na false i powiadomią wszystkie oczekujące wątki.
Kilka wskazówek, o których należy pamiętać o zamkach:
- W Javie każdy obiekt ma blokadę lub monitor. Dostęp do tej blokady można uzyskać za pomocą wątku.
- W danej chwili tylko jeden wątek może przejąć ten monitor lub blokadę.
- Język programowania Java udostępnia słowo kluczowe Synchronized ”, które pozwala nam synchronizować wątki przez utworzenie bloku lub metody jako Synchronizowane.
- Współdzielone zasoby, do których wątki muszą uzyskać dostęp, są przechowywane w tym zsynchronizowanym bloku / metodzie.
Muteksy w Javie
Omówiliśmy już, że w środowisku wielowątkowym warunki wyścigu mogą wystąpić, gdy więcej niż jeden wątek próbuje uzyskać dostęp do współdzielonych zasobów jednocześnie, a warunki wyścigu powodują nieoczekiwane wyniki.
Część programu, która próbuje uzyskać dostęp do udostępnionego zasobu, nosi nazwę 'Krytyczny fragment' . Aby uniknąć wystąpienia warunków wyścigu, istnieje potrzeba zsynchronizowania dostępu do odcinka krytycznego. Synchronizując tę krytyczną sekcję, upewniamy się, że tylko jeden wątek ma dostęp do krytycznej sekcji w danym momencie.
Najprostszym rodzajem synchronizatora jest „mutex”. Mutex zapewnia, że w danym przypadku tylko jeden wątek może wykonać sekcję krytyczną.
Muteks jest podobny do koncepcji monitorów lub blokad, które omówiliśmy powyżej. Jeśli wątek musi uzyskać dostęp do sekcji krytycznej, musi uzyskać muteks. Po uzyskaniu muteksu wątek uzyska dostęp do kodu sekcji krytycznej, a po zakończeniu zwolni muteks.
Pozostałe wątki oczekujące na dostęp do sekcji krytycznej zostaną w międzyczasie zablokowane. Gdy tylko wątek zawierający mutex zwolni go, kolejny wątek wejdzie do sekcji krytycznej.
jak otworzyć plik dat na komputerze Mac
Istnieje kilka sposobów implementacji muteksu w Javie.
- Używanie zsynchronizowanych słów kluczowych
- Korzystanie z semafora
- Korzystanie z ReentrantLock
W tym samouczku omówimy pierwsze podejście, tj. Synchronizację. Pozostałe dwa podejścia - Semaphore i ReentrantLock zostaną omówione w następnym samouczku, w którym omówimy pakiet współbieżny Java.
Zsynchronizowane słowo kluczowe
Java udostępnia słowo kluczowe „Synchronized”, którego można użyć w programie do oznaczenia sekcji krytycznej. Sekcja krytyczna może być blokiem kodu lub pełną metodą. Dlatego tylko jeden wątek może uzyskać dostęp do sekcji krytycznej oznaczonej słowem kluczowym Synchronized.
Możemy napisać współbieżne części (części, które są wykonywane jednocześnie) dla aplikacji przy użyciu słowa kluczowego Synchronized. Pozbywamy się również warunków wyścigu, tworząc blok kodu lub metodę Synchronized.
Kiedy oznaczymy blok lub metodę jako synchronizowaną, chronimy współdzielone zasoby wewnątrz tych jednostek przed jednoczesnym dostępem, a tym samym korupcją.
Rodzaje synchronizacji
Istnieją 2 rodzaje synchronizacji, jak wyjaśniono poniżej:
# 1) Synchronizacja procesów
Synchronizacja procesów obejmuje jednoczesne wykonywanie wielu procesów lub wątków. Ostatecznie osiągają stan, w którym te procesy lub wątki zobowiązują się do określonej sekwencji działań.
# 2) Synchronizacja wątków
W synchronizacji wątków więcej niż jeden wątek próbuje uzyskać dostęp do udostępnionej przestrzeni. Wątki są synchronizowane w taki sposób, że współdzielona przestrzeń jest dostępna tylko dla jednego wątku na raz.
Synchronizacja procesów jest poza zakresem tego samouczka. Dlatego będziemy tutaj omawiać tylko synchronizację wątków.
W Javie możemy użyć słowa kluczowego synchronized z:
- Blok kodu
- Metoda
Powyższe typy są wzajemnie wykluczającymi się typami synchronizacji wątków. Wzajemne wykluczenie sprawia, że wątki uzyskujące dostęp do udostępnionych danych nie kolidują ze sobą.
Innym rodzajem synchronizacji wątków jest „komunikacja między wątkami” oparta na współpracy między wątkami. Komunikacja między wątkami jest poza zakresem tego samouczka.
Zanim przejdziemy do synchronizacji bloków i metod, zaimplementujmy program Java, aby zademonstrować zachowanie wątków, gdy nie ma synchronizacji.
Wielowątkowość bez synchronizacji
Poniższy program Java zawiera wiele wątków, które nie są zsynchronizowane.
class PrintCount { //method to print the thread counter public void printcounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run method for thread public void run() { PD.printcounter(); System.out.println('Thread ' + threadName + ' exiting.'); } //start method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create two instances of thread class ThreadCounter T1 = new ThreadCounter( 'ThreadCounter_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'ThreadCounter_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Wynik
Na podstawie danych wyjściowych widać, że ponieważ wątki nie są zsynchronizowane, dane wyjściowe są niespójne. Oba wątki rozpoczynają się, a następnie wyświetlają licznik jeden po drugim. Obie nitki wychodzą na końcu.
Z podanego programu pierwszy wątek powinien zostać zakończony po wyświetleniu wartości liczników, a następnie drugi wątek powinien zacząć wyświetlać wartości liczników.
Teraz przejdźmy do synchronizacji i zacznijmy od synchronizacji bloku kodu.
Zsynchronizowany blok kodu
Zsynchronizowany blok jest używany do synchronizacji bloku kodu. Ten blok zwykle składa się z kilku wierszy. Zsynchronizowany blok jest używany, gdy nie chcemy, aby cała metoda była synchronizowana.
Na przykład, mamy metodę z, powiedzmy, 75 liniami kodu. Z tego tylko 10 linii kodu jest wymaganych do wykonania przez jeden wątek na raz. W takim przypadku, jeśli sprawimy, że cała metoda będzie zsynchronizowana, będzie to obciążenie dla systemu. W takich sytuacjach wybieramy zsynchronizowane bloki.
Zakres metody synchronizowanej jest zawsze mniejszy niż zakres metody synchronicznej. Zsynchronizowana metoda blokuje obiekt udostępnionego zasobu, który ma być używany przez wiele wątków.
Ogólna składnia zsynchronizowanego bloku jest przedstawiona poniżej:
synchronized (lock_object){ //synchronized code statements }
Tutaj „lock_object” jest wyrażeniem odniesienia do obiektu, na którym ma zostać uzyskana blokada. Tak więc zawsze, gdy wątek chce uzyskać dostęp do zsynchronizowanych instrukcji wewnątrz bloku w celu wykonania, musi uzyskać blokadę na monitorze „lock_object”.
Jak już wspomniano, słowo kluczowe synchronized zapewnia, że tylko jeden wątek może uzyskać blokadę na raz, a wszystkie inne wątki muszą czekać, aż wątek trzymający blokadę zakończy działanie i zwolni blokadę.
Uwaga
najlepsze miejsce do oglądania dubbingowanego anime za darmo
- Jeśli używany obiekt lock_object ma wartość Null, generowany jest wyjątek „NullPointerException”.
- Jeśli wątek śpi, wciąż trzymając blokadę, blokada nie zostaje zwolniona. Inne wątki nie będą miały dostępu do udostępnionego obiektu w tym czasie uśpienia.
Teraz przedstawimy powyższy przykład, który został już wdrożony z niewielkimi zmianami. We wcześniejszym programie nie synchronizowaliśmy kodu. Teraz użyjemy zsynchronizowanego bloku i porównamy dane wyjściowe.
Wielowątkowość z synchronizacją
W poniższym programie Java używamy zsynchronizowanego bloku. W metodzie run synchronizujemy kod linii wyświetlających licznik dla każdego wątku.
class PrintCount { //print thread counter public void printCounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run () method for thread with synchronized block public void run() { synchronized(PD) { PD.printCounter(); } System.out.println('Thread ' + threadName + ' exiting.'); } //start () method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create thread instances ThreadCounter T1 = new ThreadCounter( 'Thread_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'Thread_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Wynik
Teraz wynik tego programu używającego zsynchronizowanego bloku jest dość spójny. Zgodnie z oczekiwaniami oba wątki zostaną uruchomione. Pierwszy wątek zakończył wyświetlanie wartości liczników i kończy pracę. Następnie drugi wątek wyświetla wartości liczników i kończy pracę.
Metoda synchroniczna
Omówmy metodę synchroniczną w tej sekcji. Wcześniej widzieliśmy, że możemy zadeklarować mały blok składający się z mniejszej liczby linii kodu jako blok zsynchronizowany. Jeśli chcemy, aby cała funkcja była zsynchronizowana, możemy zadeklarować metodę jako zsynchronizowaną.
Gdy metoda zostanie zsynchronizowana, tylko jeden wątek będzie mógł wywołać metodę w danym momencie.
Ogólna składnia pisania metody synchronicznej jest następująca:
synchronized method_name (parameters){ //synchronized code }
Podobnie jak w przypadku zsynchronizowanego bloku, w przypadku metody synchronizowanej potrzebujemy obiektu lock_object, który będzie używany przez wątki korzystające z metody synchronizowanej.
W przypadku metody synchronicznej obiekt blokady może być jednym z następujących:
- Jeśli metoda synchroniczna jest statyczna, obiekt blokady jest podawany przez obiekt „.class”.
- W przypadku metody niestatycznej obiekt blokady jest podawany przez bieżący obiekt, tj. „Ten” obiekt.
Osobliwą cechą słowa kluczowego zsynchronizowanego jest to, że jest ono powtórne. Oznacza to, że zsynchronizowana metoda może wywołać inną zsynchronizowaną metodę z tą samą blokadą. Zatem wątek utrzymujący blokadę może uzyskać dostęp do innej zsynchronizowanej metody bez konieczności uzyskiwania innej blokady.
Poniższy przykład ilustruje metodę synchronizowaną.
class NumberClass { //synchronized method to print squares of numbers synchronized void printSquares(int n) throws InterruptedException { //iterate from 1 to given number and print the squares at each iteration for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + ' :: '+ i*i); Thread.sleep(500); } } } public class Main { public static void main(String args()) { final NumberClass number = new NumberClass(); //create thread Runnable thread = new Runnable() { public void run() { try { number.printSquares(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; //start thread instance new Thread(thread, 'Thread One').start(); new Thread(thread, 'Thread Two').start(); } }
Wynik
W powyższym programie użyliśmy zsynchronizowanej metody do wydrukowania kwadratów liczby. Górna granica liczby jest przekazywana do metody jako argument. Następnie począwszy od 1, kwadraty każdej liczby są drukowane, aż do osiągnięcia górnej granicy.
W funkcji głównej tworzona jest instancja wątku. Do każdego wystąpienia wątku przekazywana jest liczba w celu wydrukowania kwadratów.
Jak wspomniano powyżej, gdy metoda, która ma zostać zsynchronizowana, jest statyczna, wówczas obiekt blokady jest związany z klasą, a nie obiektem. Oznacza to, że będziemy blokować klasę, a nie obiekt. Nazywa się to synchronizacją statyczną.
Inny przykład podano poniżej.
class Table{ //synchronized static method to print squares of numbers synchronized static void printTable(int n){ for(int i=1;i<=10;i++){ System.out.print(n*i + ' '); try{ Thread.sleep(400); }catch(Exception e){} } System.out.println(); } } //thread class Thread_One class Thread_One extends Thread{ public void run(){ Table.printTable(2); } } //thread class Thread_Two class Thread_Two extends Thread{ public void run(){ Table.printTable(5); } } public class Main{ public static void main(String t()){ //create instances of Thread_One and Thread_Two Thread_One t1=new Thread_One (); Thread_Two t2=new Thread_Two (); //start each thread instance t1.start(); t2.start(); } }
Wynik
W powyższym programie drukujemy tabliczki mnożenia liczb. Każda liczba, której tabela ma zostać wydrukowana, jest instancją wątku o innej klasie wątku. W ten sposób wypisujemy tablice mnożenia 2 i 5, więc mamy dwie klasy thread_one i thread_two do wypisania odpowiednio tabel 2 i 5.
Podsumowując, słowo kluczowe Java synchronized spełnia następujące funkcje:
- Synchronized słowo kluczowe w Javie gwarantuje wzajemnie wykluczający się dostęp do współdzielonych zasobów, zapewniając mechanizm blokujący. Blokowanie zapobiega również warunkom wyścigu.
- Używając słowa kluczowego synchronized, zapobiegamy współbieżnym błędom programowania w kodzie.
- Gdy metoda lub blok jest zadeklarowany jako zsynchronizowany, wątek wymaga blokady na wyłączność, aby przejść do zsynchronizowanej metody lub bloku. Po wykonaniu niezbędnych czynności wątek zwalnia blokadę i opróżnia operację zapisu. W ten sposób wyeliminuje błędy pamięci związane z niespójnością.
Nietrwały w Javie
Słowo kluczowe volatile w Javie jest używane do zapewnienia bezpieczeństwa wątków klas. Używamy również słowa kluczowego volatile do modyfikowania wartości zmiennej przez różne wątki. Słowo kluczowe volatile może służyć do deklarowania zmiennej z typami pierwotnymi oraz obiektami.
W niektórych przypadkach słowo kluczowe volatile jest używane jako alternatywa dla słowa kluczowego synchronized, ale należy pamiętać, że nie zastępuje ono słowa kluczowego synchronized.
Gdy zmienna jest zadeklarowana jako ulotna, jej wartość nigdy nie jest buforowana, ale zawsze jest odczytywana z pamięci głównej. Zmienna zmienna gwarantuje porządkowanie i widoczność. Chociaż zmienną można zadeklarować jako zmienną, nie możemy deklarować klas lub metod jako nietrwałych.
Rozważmy następujący blok kodu:
class ABC{ static volatile int myvar =10; }
W powyższym kodzie zmienna myvar jest statyczna i niestabilna. Zmienna statyczna jest wspólna dla wszystkich obiektów klas. Zmienna ulotna zawsze znajduje się w pamięci głównej i nigdy nie jest buforowana.
W związku z tym w pamięci głównej będzie tylko jedna kopia myvar i wszystkie operacje odczytu / zapisu będą wykonywane na tej zmiennej z pamięci głównej. Gdyby myvar nie został zadeklarowany jako niestabilny, każdy obiekt wątku miałby inną kopię, co spowodowałoby niespójności.
Poniżej wymieniono niektóre różnice między słowami kluczowymi zmiennymi i zsynchronizowanymi.
Zmienne słowo kluczowe | Synchronizowane słowo kluczowe |
---|---|
Słowo kluczowe volatile jest używane tylko w przypadku zmiennych. | Słowo kluczowe synchronized jest używane z blokami kodu i metodami. |
Nietrwałe słowo kluczowe nie może zablokować wątku oczekiwania. | Słowo kluczowe synchronized może zablokować oczekiwanie wątku. |
Wydajność wątku jest lepsza dzięki Volatile. | Wydajność wątku nieco spada z synchronizacją. |
Zmienne ulotne znajdują się w pamięci głównej. | Zsynchronizowane konstrukcje nie znajdują się w pamięci głównej. |
Volatile synchronizuje jednocześnie jedną zmienną między pamięcią wątku a pamięcią główną. | Synchronizowane słowo kluczowe synchronizuje jednocześnie wszystkie zmienne. |
Impas w Javie
Widzieliśmy, że możemy synchronizować wiele wątków za pomocą słowa kluczowego synchronized i sprawić, by programy były bezpieczne dla wątków. Synchronizując wątki, zapewniamy, że wiele wątków jest wykonywanych jednocześnie w środowisku wielowątkowym.
Czasami jednak zdarza się sytuacja, w której wątki nie mogą już działać jednocześnie. Zamiast tego czekają bez końca. Dzieje się tak, gdy jeden wątek oczekuje na zasób, a ten zasób jest blokowany przez drugi wątek.
Z drugiej strony drugi wątek oczekuje na zasób, który jest blokowany przez pierwszy wątek. Taka sytuacja powoduje „impas” w Javie.
Poniższy obraz przedstawia impas w Javie.
Jak widać na powyższym diagramie, wątek A zablokował zasób r1 i czeka na zasób r2. Z drugiej strony wątek B zablokował zasób r2 i czeka na r1.
W ten sposób żaden z wątków nie może zakończyć wykonania, dopóki nie przejmie oczekujących zasobów. Sytuacja ta doprowadziła do impasu, w którym oba wątki bez końca czekają na zasoby.
Poniżej podano przykład zakleszczeń w Javie.
public class Main { public static void main(String() args) { //define shared resources final String shared_res1 = 'Java tutorials'; final String shared_res2 = 'Multithreading'; // thread_one => locks shared_res1 then shared_res2 Thread thread_one = new Thread() { public void run() { synchronized (shared_res1) { System.out.println('Thread one: locked shared resource 1'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res2) { System.out.println('Thread one: locked shared resource 2'); } } } }; // thread_two=> locks shared_res2 then shared_res1 Thread thread_two = new Thread() { public void run() { synchronized (shared_res2) { System.out.println('Thread two: locked shared resource 2'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res1) { System.out.println('Thread two: locked shared resource 1'); } } } }; //start both the threads thread_one.start(); thread_two.start(); } }
Wynik
W powyższym programie mamy dwa współdzielone zasoby i dwa wątki. Oba wątki po kolei próbują uzyskać dostęp do udostępnionych zasobów. Dane wyjściowe pokazują, że oba wątki blokują jeden zasób, czekając na pozostałe. W ten sposób tworząc sytuację impasu.
Chociaż nie możemy całkowicie zapobiec wystąpieniu impasu, z pewnością możemy ich uniknąć, podejmując pewne kroki.
Poniżej wymieniono sposoby, dzięki którym możemy uniknąć zakleszczeń w Javie.
# 1) Unikając zagnieżdżonych blokad
Posiadanie zagnieżdżonych zamków jest najważniejszym powodem występowania zakleszczeń. Zagnieżdżone blokady to blokady nadawane wielu wątkom. Dlatego powinniśmy unikać blokowania więcej niż jednego wątku.
# 2) Użyj wątku Join
Powinniśmy używać Thread.join z maksymalnym czasem, aby wątki mogły wykorzystać maksymalny czas na wykonanie. Zapobiegnie to zakleszczeniu, które występuje najczęściej, gdy jeden wątek ciągle czeka na inne.
# 3) Unikaj niepotrzebnych blokad
Powinniśmy zablokować tylko niezbędny kod. Posiadanie niepotrzebnych blokad dla kodu może prowadzić do zakleszczenia w programie. Ponieważ zakleszczenia mogą złamać kod i utrudnić przepływ programu, powinniśmy być skłonni unikać zakleszczeń w naszych programach.
Często Zadawane Pytania
P 1) Co to jest synchronizacja i dlaczego jest ważna?
Odpowiedź: Synchronizacja to proces kontrolowania dostępu współdzielonego zasobu do wielu wątków. Bez synchronizacji wiele wątków może aktualizować lub zmieniać współdzielony zasób w tym samym czasie, powodując niespójności.
Dlatego powinniśmy zapewnić, że w środowisku wielowątkowym wątki są zsynchronizowane, tak aby sposób, w jaki uzyskują dostęp do współdzielonych zasobów, był wzajemnie wykluczający się i spójny.
Pytanie 2) Co to jest synchronizacja i brak synchronizacji w Javie?
Odpowiedź: Synchronizacja oznacza, że konstrukcja jest bezpieczna dla wątków. Oznacza to, że wiele wątków nie może jednocześnie uzyskać dostępu do konstrukcji (bloku kodu, metody itp.).
Konstrukcje niezsynchronizowane nie są bezpieczne dla wątków. Wiele wątków może w dowolnym momencie uzyskać dostęp do niezsynchronizowanych metod lub bloków. Popularną niezsynchronizowaną klasą w Javie jest StringBuilder.
Pytanie 3) Dlaczego wymagana jest synchronizacja?
Odpowiedź: Gdy procesy muszą być wykonywane jednocześnie, potrzebujemy synchronizacji. Dzieje się tak, ponieważ potrzebujemy zasobów, które mogą być współdzielone przez wiele procesów.
Aby uniknąć kolizji między procesami lub wątkami w celu uzyskania dostępu do współdzielonych zasobów, musimy zsynchronizować te zasoby, aby wszystkie wątki miały dostęp do zasobów, a aplikacja również działała płynnie.
P # 4) Jak uzyskać zsynchronizowaną listę ArrayList?
Odpowiedź: Możemy użyć metody listy Collections.synchronized z ArrayList jako argumentem do konwersji ArrayList do zsynchronizowanej listy.
P # 5) Czy HashMap jest zsynchronizowany?
jak skopiować tablicę java
Odpowiedź: Nie, HashMap nie jest synchronizowany, ale HashTable jest synchronizowany.
Wniosek
W tym samouczku szczegółowo omówiliśmy synchronizację wątków. Wraz z nim dowiedzieliśmy się również o słowie kluczowym volatile i zakleszczeniach w Javie. Synchronizacja składa się z synchronizacji procesów i wątków.
W środowisku wielowątkowym bardziej interesuje nas synchronizacja wątków. Widzieliśmy tutaj podejście zsynchronizowanych słów kluczowych do synchronizacji wątków.
Zakleszczenie to sytuacja, w której wiele wątków bez końca czeka na zasoby. Widzieliśmy przykład zakleszczeń w Javie wraz z metodami unikania zakleszczeń w Javie.
=> Odwiedź tutaj, aby nauczyć się języka Java od podstaw.
rekomendowane lektury
- Thread.Sleep () - Metoda Thread Sleep () w języku Java z przykładami
- Wątki Java z metodami i cyklem życia
- Podstawy języka Java: składnia języka Java, klasa języka Java i podstawowe pojęcia dotyczące języka Java
- Wielowątkowość w Javie - samouczek z przykładami
- Wielowątkowość w C ++ z przykładami
- Samouczek JAVA dla początkujących: ponad 100 praktycznych samouczków wideo Java
- Komponenty Java: platforma Java, JDK, JRE i wirtualna maszyna Java
- Samouczek dotyczący ciągów Java | Metody ciągów Java z przykładami