2014-09-29 16 views
12

Pracuję nad kodem Java, muszę zaimplementować w nim wątki. Przeszedłem przez API JAVA 8 i dowiedziałem się o Stamped Locks. Czy ktoś może mi powiedzieć, dlaczego używać StampedLocks w wielowątkowości?Co to jest StampedLock w Javie?

Z góry dziękuję.

+2

Co to jest _normalny wielowątkowość_? – Keppil

+0

@ SimY4 Właśnie czytałem o Stemplowanych blokadach tylko w dokumencie. Potem googlowałem. Ale nie mam jasnego pojęcia, dlaczego powinniśmy go używać. Musi istnieć jakaś zaleta korzystania z pieczęci Stamped, dlatego Oracle wprowadza ją w java 8. – Mohit

+0

@Keppil Zmieniłem moje pytanie. Dzięki za poprawienie mnie. – Mohit

Odpowiedz

14

StampedLock jest alternatywą dla korzystania z ReadWriteLock (implementowane przez ReentrantReadWriteLock). Główne różnice między StampedLock i ReentrantReadWriteLock są następujące:

  • StampedLocks umożliwiają blokowanie optymistyczne dla operacji odczytu
  • ReentrantLocks są wklęsłego (StampedLocks nie są)

Więc jeśli masz scenariusz, gdzie trzeba rywalizacji (w przeciwnym razie możesz równie dobrze używać synchronized lub prostego Lock) i więcej czytników niż pisarzy, używanie StampedLock może znacznie poprawić wydajność.

Należy jednak zmierzyć wydajność w oparciu o konkretny przypadek użycia przed przystąpieniem do wyciągania wniosków.

Heinz Kabutz napisał o StampedLocks in his newsletter, a także wykonał a presentation about performance.

+0

Dzięki, Teraz znam przypadek, w którym mogę go użyć i mam o nim jasny pogląd. – Mohit

+0

@Mohit, podążaj za linkiem, aby lepiej poznać StampedLock: https://dzone.com/articles/a-look-at-stampedlock – Roshan

+0

Artykuł Heinza doskonale wyjaśnił wszystkie mechanizmy synchronizacji za pomocą krótkiego przykładu. Dzięki! –

5

Dokumentacja API dla java.util.concurrent.locks.StampedLock mówi:

StampedLocks przeznaczone są do stosowania jako narzędzi wewnętrznych w rozwoju komponentów wątku bezpieczny. Ich wykorzystanie polega na znajomości wewnętrznych właściwości danych, obiektów i metod, które chronią. Nie są one reentrantami, więc zamknięte ciała nie powinny wywoływać innych nieznanych metod, które mogą próbować ponownie pozyskać zamki (chociaż możesz przekazać pieczęć innym metodom, które mogą go użyć lub przekonwertować). Korzystanie z trybów odczytywania blokad polega na tym, że powiązane sekcje kodu są pozbawione efektu ubocznego. Nieprawidłowe sekcje odczytu optymistycznego nie mogą wywoływać metod, które nie są tolerowane przez potencjalne niespójności. Znaczki używają skończonych reprezentacji i nie są bezpieczne pod względem kryptograficznym (to znaczy, można zgadnąć, że ważny znaczek jest możliwy). Wartości stempla mogą być ponownie wykorzystane po (nie wcześniej niż) roku nieprzerwanej pracy. Pieczęć przechowywana bez użycia lub zatwierdzenia przez dłużej niż ten okres może nie zostać poprawnie zatwierdzona. StampedLocks można szeregować, ale zawsze deserializować do stanu początkowego odblokowania, dlatego nie są przydatne do zdalnego blokowania.

np. -

class Point { 
    private double x, y; 
    private final StampedLock sl = new StampedLock(); 

    void move(double deltaX, double deltaY) { // an exclusively locked method 
    long stamp = sl.writeLock(); 
    try { 
     x += deltaX; 
     y += deltaY; 
    } finally { 
     sl.unlockWrite(stamp); 
    } 
    } 

    double distanceFromOrigin() { // A read-only method 
    long stamp = sl.tryOptimisticRead(); 
    double currentX = x, currentY = y; 
    if (!sl.validate(stamp)) { 
     stamp = sl.readLock(); 
     try { 
      currentX = x; 
      currentY = y; 
     } finally { 
      sl.unlockRead(stamp); 
     } 
    } 
    return Math.sqrt(currentX * currentX + currentY * currentY); 
    } 

    void moveIfAtOrigin(double newX, double newY) { // upgrade 
    // Could instead start with optimistic, not read mode 
    long stamp = sl.readLock(); 
    try { 
     while (x == 0.0 && y == 0.0) { 
     long ws = sl.tryConvertToWriteLock(stamp); 
     if (ws != 0L) { 
      stamp = ws; 
      x = newX; 
      y = newY; 
      break; 
     } 
     else { 
      sl.unlockRead(stamp); 
      stamp = sl.writeLock(); 
     } 
     } 
    } finally { 
     sl.unlock(stamp); 
    } 
    } 
} 
1

StampedLock obsługuje blokady odczytu i zapisu. W przeciwieństwie do ReadWriteLock, metody blokowania StampedLock zwracają znaczek reprezentowany przez długą wartość. Możesz użyć tych znaczków, aby zwolnić blokadę lub sprawdzić, czy blokada jest nadal ważna. Dodatkowo wybite zatrzaski obsługują inny tryb blokowania nazywany optymistycznym blokowaniem.

ExecutorService executor = Executors.newFixedThreadPool(2); 
     Map<String, String> map = new HashMap<>(); 
     StampedLock lock = new StampedLock(); 

     executor.submit(() -> { 
      long stamp = lock.writeLock(); 
      try { 
       Thread.sleep(100); 
       map.put("test", "INDIA"); 
      } catch (Exception e) { 
      } finally { 
       lock.unlockWrite(stamp); 
      } 
     }); 

     Runnable readTask =() -> { 
      long stamp = lock.readLock(); 
      try { 
       System.out.println(map.get("test")); 
       Thread.sleep(100); 
      } catch (Exception e) { 
      } finally { 
       lock.unlockRead(stamp); 
      } 
     }; 

     executor.submit(readTask); 
     executor.submit(readTask); 

Uzyskanie odczytu lub zapisu blokadę poprzez readLock() lub writelock() zwraca stempel, który jest później używany do odblokowania w obrębie bloku finally. Należy pamiętać, że wybite zatrzaski nie wprowadzają cech charakterystycznych. Każde wezwanie do zablokowania zwraca nową pieczęć i blokuje, jeśli żadna blokada nie jest dostępna, nawet jeśli ten sam wątek już posiada blokadę. Musisz więc zwrócić szczególną uwagę, aby nie wpaść w zakleszczenia.

executor.submit(() -> { 
      long stamp = lock.tryOptimisticRead(); 
      try { 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
       Thread.sleep(100); 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
       Thread.sleep(1000); 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
      } catch (Exception e) { 
      } finally { 
       lock.unlock(stamp); 
      } 
     }); 

     executor.submit(() -> { 
      long stamp = lock.writeLock(); 
      try { 
       System.out.println("Write Lock acquired"); 
       Thread.sleep(100); 
      } catch (Exception e) { 
      } finally { 
       lock.unlock(stamp); 
       System.out.println("Write done"); 
      } 
     }); 

Optymistyczne blokada odczytu nabyte przez wywołanie tryOptimisticRead(), która zwraca zawsze znaczek bez blokowania bieżącego wątku, nie ważne czy blokada jest rzeczywiście dostępny. Jeśli jest już aktywna blokada zapisu, zwracany znacznik jest równy zeru. Zawsze możesz sprawdzić, czy pieczęć jest ważna, dzwoniąc lock.validate (pieczęć).