3.1 Obiekt aktywny
Obiekt aktywny to wzorzec projektowy, który oddziela wątek wykonania metody od wątku, w którym została ona wywołana. Celem tego wzorca jest zapewnienie wykonywania równoległego przy użyciu wywołań metod asynchronicznych i harmonogramu przetwarzania żądań.
Uproszczona wersja:
Klasyczny wariant:
Ten szablon ma sześć elementów:
- Obiekt proxy, który zapewnia interfejs do publicznych metod klienta.
- Interfejs definiujący metody dostępu do aktywnego obiektu.
- Lista przychodzących żądań od klientów.
- Harmonogram określający kolejność wykonywania zapytań.
- Implementacja metod obiektów aktywnych.
- Procedura wywołania zwrotnego lub zmienna dla klienta, aby otrzymać wynik.
3.2 zamek
Wzorzec blokady to mechanizm synchronizacji, który umożliwia wyłączny dostęp do udostępnionego zasobu między wieloma wątkami. Blokady to jeden ze sposobów wymuszania zasad kontroli współbieżności.
Zasadniczo używana jest miękka blokada, przy założeniu, że każdy wątek próbuje „uzyskać blokadę” przed uzyskaniem dostępu do odpowiedniego udostępnionego zasobu.
Jednak niektóre systemy zapewniają obowiązkowy mechanizm blokowania, dzięki któremu nieautoryzowana próba dostępu do zablokowanego zasobu zostanie przerwana przez zgłoszenie wyjątku dla wątku, który próbował uzyskać dostęp.
Semafor jest najprostszym rodzajem zamka. W zakresie dostępu do danych nie rozróżnia się trybów dostępu: współdzielony (tylko do odczytu) lub wyłączny (odczyt i zapis). W trybie współdzielonym wiele wątków może zażądać blokady dostępu do danych w trybie tylko do odczytu. Tryb wyłącznego dostępu jest również używany w algorytmach aktualizacji i usuwania.
Rodzaje blokad wyróżnia strategia blokowania kontynuacji wykonywania wątku. W większości implementacji żądanie blokady uniemożliwia kontynuowanie wykonywania wątku, dopóki zablokowany zasób nie będzie dostępny.
Spinlock to blokada, która czeka w pętli na przyznanie dostępu. Taka blokada jest bardzo wydajna, jeśli wątek czeka na blokadę przez niewielką ilość czasu, unikając w ten sposób nadmiernego ponownego planowania wątków. Koszt oczekiwania na dostęp będzie znaczny, jeśli jeden z wątków długo trzyma zamek.
Aby skutecznie wdrożyć mechanizm blokujący, wymagane jest wsparcie na poziomie sprzętowym. Obsługa sprzętu może być zaimplementowana jako jedna lub więcej operacji atomowych, takich jak „przetestuj i ustaw”, „pobierz i dodaj” lub „porównaj i zamień”. Takie instrukcje pozwalają bez przerwy sprawdzać, czy zamek jest wolny, a jeśli tak, to zdobyć zamek.
3.3 Monitoruj
Wzorzec Monitor to mechanizm interakcji i synchronizacji procesów wysokiego poziomu, który zapewnia dostęp do współdzielonych zasobów. Podejście do synchronizacji dwóch lub więcej zadań komputerowych przy użyciu wspólnego zasobu, zwykle sprzętu lub zestawu zmiennych.
W przypadku wielozadaniowości opartej na monitorze kompilator lub interpreter w sposób przezroczysty wstawia kod blokujący-odblokowujący do odpowiednio sformatowanych procedur, w sposób przejrzysty dla programisty, oszczędzając programiście jawnego wywoływania prymitywów synchronizacji.
Monitor składa się z:
- zestaw procedur wchodzących w interakcje z udostępnionym zasobem
- muteks
- zmienne powiązane z tym zasobem
- niezmiennik, który definiuje warunki, aby uniknąć sytuacji wyścigu
Procedura monitora uzyskuje muteks przed rozpoczęciem pracy i wstrzymuje go do zakończenia procedury lub do czasu oczekiwania na określony warunek. Jeśli każda procedura gwarantuje, że niezmiennik jest prawdziwy przed zwolnieniem muteksu, żadne zadanie nie może uzyskać zasobu w warunkach wyścigu.
W ten sposób operator synchronizacji działa w Javie z metodami wait()
i notify()
.
3.4 Podwójna kontrola blokady
Podwójnie sprawdzane blokowanie to równoległy wzór projektowy mający na celu zmniejszenie narzutu związanego z uzyskaniem zamka.
Najpierw warunek blokowania jest sprawdzany bez jakiejkolwiek synchronizacji. Wątek próbuje uzyskać blokadę tylko wtedy, gdy wynik sprawdzenia wskazuje, że musi uzyskać blokadę.
//Double-Checked Locking
public final class Singleton {
private static Singleton instance; //Don't forget volatile modifier
public static Singleton getInstance() {
if (instance == null) { //Read
synchronized (Singleton.class) { //
if (instance == null) { //Read Write
instance = new Singleton(); //
}
}
}
}
Jak utworzyć obiekt singleton w środowisku bezpiecznym dla wątków?
public static Singleton getInstance() {
if (instance == null)
instance = new Singleton();
}
Jeśli tworzysz obiekt Singleton z różnych wątków, to może dojść do sytuacji, w której tworzonych jest kilka obiektów jednocześnie, a to jest niedopuszczalne. Dlatego rozsądne jest zawinięcie tworzenia obiektu w zsynchronizowaną instrukcję.
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null)
instance = new Singleton();
}
}
To podejście zadziała, ale ma małą wadę. Po utworzeniu obiektu, za każdym razem, gdy spróbujesz go zdobyć w przyszłości, w zsynchronizowanym bloku zostanie wykonane sprawdzenie, co oznacza, że bieżący wątek i wszystko, co jest z nim związane, zostanie zablokowane. Więc ten kod można nieco zoptymalizować:
public static Singleton getInstance() {
if (instance != null)
return instance;
synchronized (Singleton.class) {
if (instance == null)
instance = new Singleton();
}
}
Na niektórych językach i/lub na niektórych komputerach nie jest możliwe bezpieczne zaimplementowanie tego wzorca. Dlatego czasami nazywany jest antywzorcem. Takie cechy doprowadziły do pojawienia się ścisłej relacji „zdarza się przed” w modelach pamięci Java i modelu pamięci C++.
Jest zwykle używany w celu zmniejszenia narzutu związanego z implementacją leniwej inicjalizacji w programach wielowątkowych, takich jak wzorzec projektowy Singleton. W leniwej inicjalizacji zmiennej inicjalizacja jest odraczana do momentu, gdy wartość zmiennej będzie potrzebna do obliczeń.
3.5 Harmonogram
Harmonogram to równoległy wzorzec projektowy, który zapewnia mechanizm wdrażania zasad planowania, ale jest niezależny od jakiejkolwiek konkretnej polityki. Kontroluje kolejność, w jakiej wątki powinny wykonywać sekwencyjny kod, używając obiektu, który jawnie określa sekwencję oczekujących wątków.
GO TO FULL VERSION