JavaRush /Blog Java /Random-PL /Co to jest zakleszczenie w Javie?
Alexey Smirnov
Poziom 29
Москва

Co to jest zakleszczenie w Javie?

Opublikowano w grupie Random-PL
Poziom wiedzy wymagany do zrozumienia artykułu: ukończyłeś zadania Java Syntax i Java Core, a teraz jesteś w trakcie nauki wielowątkowości Java. Zakleszczenie lub zakleszczenie w Javie lub zakleszczenie to błąd występujący, gdy wątki mają cykliczną zależność od pary zsynchronizowanych obiektów. Wyobraź sobie, że jeden wątek przechodzi do monitora obiektów x, a drugi do monitora obiektów y. Jeśli wątek w obiekcie xspróbuje wywołać na obiekcie dowolną zsynchronizowaną metodę y, a obiekt yw tym samym czasie spróbuje wywołać na obiekcie dowolną zsynchronizowaną metodę x, wątki utkną w oczekiwaniu. Co to jest zakleszczenie?  - 1Poniżej znajduje się przykład z samouczka dokumentacji Java dotyczący takiego pojęcia jak zakleszczenie. Gdzie występuje tutaj blokowanie wątków?
public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            @Override
            public void run() {
               // System.out.println("Thread 1");
                alphonse.bow(gaston);
               // System.out.println("Th: gaston bowed to alphonse");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
              //  System.out.println("Thread 2");
                gaston.bow(alphonse);
              //  System.out.println("2.gaston waiting alph bowed");
            }
        }).start();
    }
}
Należy tu zrozumieć dwie ważne rzeczy:
  1. Co dokładnie robi każdy z jednocześnie uruchomionych wątków?
  2. Jakie zamki są stosowane?
Zacznijmy od końca. Załóżmy, że utworzyłeś dwa obiekty klasy Friend: alphonsei gaston. Każdy z nich ma swój własny zamek. Zatem istnieją dwa takie zamki: gigolos i gastons. Po wejściu do zsynchronizowanej metody obiektu jego blokada zostaje zablokowana, a po wyjściu z metody zostaje ona zwolniona (lub odblokowana). Teraz o nitkach. Nazwijmy pierwszy wątek Alphonse(dużą literą dla odróżnienia go od dopełnienia alphonse). Oto, co robi (nazwijmy to A, w skrócie Alphonse):
A: alphonse.bow(gaston) — получает лок alphonse;
A: gaston.bowBack(alphonse) — получает лок gaston;
A: возвращается из обоих методов, тем самым освобождая лок.
A oto co wątek robi w tym momencie Gaston:
G: gaston.bow(alphonse) — получает лок gaston;
G: alphonse.bowBack(gaston) — получает лок alphonse;
G: возвращается из обоих методов, тем самым освобождая лок.
Teraz połączmy te dane i uzyskajmy odpowiedź. Wątki mogą się przeplatać (tzn. ich zdarzenia będą zachodzić) w różnej kolejności. Zakleszczenie zadziała np. jeśli kolejność będzie następująca:
A: alphonse.bow(gaston) — получает лок alphonse
G: gaston.bow(alphonse) — получает лок gaston
G: пытается вызвать alphonse.bowBack(gaston), но блокируется, ожидая лока alphonse
A: пытается вызвать gaston.bowBack(alphonse), но блокируется, ожидая лока gaston
Co to jest zakleszczenie?  - 2
W tym przypadku oba wątki są zablokowane i każdy czeka, aż drugi zwolni blokadę. Ale żaden z nich tego nie zrobi, ponieważ aby to zrobić, muszą dokończyć swoją metodę, a jest ona blokowana przez inny wątek. Utknęli więc tam, gdzie to się wydarzyło deadlock. Możliwy jest jednak również inny splot, w którym jeden z wątków będzie miał czas na ukończenie przed rozpoczęciem drugiego:
A: alphonse.bow(gaston) — получает лок alphonse
A: gaston.bowBack(alphonse) — получает лок gaston
A: возвращается из обоих методов, открывая оба лока
G: gaston.bow(alphonse) — получает лок gaston
G: alphonse.bowBack(gaston) — получает лок alphonse
G: возвращается из обоих методов, открывая оба лока
W takim przypadku nie ma mowy o wzajemnym blokowaniu wątków. Na przykład dodano metodę, która pozwala innemu wątkowi mieć czas na wykonanie. Gdy wynik zależy od kolejności jednocześnie występujących zdarzeń (planowana kolejność lub szybkość wykonania), proces taki nazywa się po rosyjsku stanem wyścigu - „stanem wyścigu”. Nie wszystkie warunki wyścigu potencjalnie powodują impas, jednak z mojego doświadczenia wynika, że ​​tylko warunki wyścigu powodują impas. Odpowiedzi udzielił: Dave Lillethun
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION