Kolekcje synchronizowane
Kolekcje synchronizowane nie mają takich metod jak putIfAbsent, ich iteratory są iteratorami fail-fast - czyli jeśli wykryją modyfikacje w trakcie iterowania wyrzucają wykątek ConcurrentModificationException. Blokowanie iteratora na czas iterowania może być bardzo kosztowne i sprawiać że program nie będzie skalowalny.
Kolekcje wielowątkowe (concurrent collections)
W javie 5 wprowadzono kolekcje wielowątkowe takie jak ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteArraySet, ArrayBlockingQueue, LinkedBlockingQueue, LinkedBlockingDequeue
ConcurrentHashMap nie synchronizuje wszystkich metod zamiast tego wykorzystywany jest tu mechanizm podziału na wiele map każda ze swoją blokadą - lock striping dzięki czemu więcej wątków może symultanicznie wykonywać operacje na obiekcie mapy. Dodatkowo mapa implementuje interfejs ConcurentMap w którym są dodatkowe atomowe metody: putIfAbsent, remove, replace. Iterator takiej mapy nie wyrzuca wyjątku jeśli mapa jest modyfikowana jednak jest iteratorem weakly consistent - czyli nie musi pokazywać zmian po utworzeniu iteratora.
CopyOnWriteArrayList jest klasą thread-safe i zastępuje ArrayList - tworzy ona kopie podległej wewnętrznej tablicy za każdym razem kiedy wykonywana jest operacja dodawania, lub usuwania obiektu - dzięki temu iterator po stworzeniu może iterować na tablicy na której został zainicjowany więc nie wyrzuci wyjątku ConcurrentModificationException. Klasa taka ma zastosowanie tam gdzie dominującą operacją jest iterowanie a nie dodawanie np. listenery.
Kolejki blokujące mogą być użyte do rozwiązania problemu producent-konsumer. Zawierają metody blokujące które czekają jeśli kolejka jest pusta lub pełna.
Kolejki dequeue umożliwają pobieranie elementów także z początku kolejki dzięki czemu mogą być używane w alborytmach work-stealing w których każdy konsument ma jedną kolejkę i jeśli nie ma więcej pracy może wziąć pracę z początku innego konsumenta - dzięki temu wątki mniej będą ze sobą walczyły (less contention) i dzięki temu rozwiązanie jest bardziej skalowalne.
Metody blokujące które rzucają wyjątek IterruptedException
Każdy wątek może zostać zablokowany lub zapauzowany z różnych powodów - oczekiwaniu na blokadzie, czekanie na skończenie operacji I/O, czekanie na wybudzenie z operacji sleep. W takim wypadku proces przechodzi w stan BLOCKED, WAITING, TIMED_WAITING. Wątek który jest zablokowany musi być czekać na operacje na którą nie ma wpływu a która go wybudzi.
Nie da się zatrzymać wątku z innego wątku - można mu tylko ustawić flagę interrupt poprzez metodę interrupt. Mechanizm ten jest w większości wykorzystywane to anulowania długo trwających operacji.
Jak obsłużyć InterruptedException:
- poprzez propagowanie go wyżej do metody wywołującej
- poprzez obsługę - jeśli nie można go wyżej propagować - poprzez restorowanie flagi interrupted: Thread.currentThread().interrupt()
Synchronizatory
Semaphore - klasa przydatna np przy pulach obiektów.
CountDownLatch - jednorazowy zatrzask który odlicza się on n do zera, wątki czekają na to aż wartość będzie równa 0. Może być użyty tylko raz.
CyclicBarrier - tak jak zatrzask blokują grupę wątków aż pewna aktywność się skończy - znana - stała liczba wątków dojdzie do bariery, następnie bariera jest resetowana a wątki mogą kontynuwać działanie. Jeśli wątek na barierze zostanie przerwany lub wystąpi timeout to reszta wątków zostanie wybudzona przez BrokenBarrierException a bariera zostanie w stanie broken.
Phaser - jest bardziej wyrafinowaną barierą, umożliwia rejestracje i wyrejestrowywanie wątków oczekujących.
Exchanger pozwala na wymianę obiektu między wątkami w miejscu "spotkania".
Brak komentarzy:
Prześlij komentarz