29 Nisan 2019 Pazartesi

StampedLock Sınıfı - Lock Üzerinde Upgrade Yapılabilir

Giriş
Şu satırı dahil ederiz
import java.util.concurrent.locks.StampedLock;
stamp Özelliği
Açıklaması şöyle.
StampedLock support read and write locks. In contrast to ReadWriteLock the locking methods of a StampedLock return a stamp represented by a long value. You can use these stamps to either release a lock or to check if the lock is still valid. Additionally stamped locks support another lock mode called optimistic locking.
Yani
- readLock() metodu stamp döner. Döndürülen stamp unlockRead() metoduna parametre olarak geçilir.

- writeLock() metodu stamp döner. Döndürülen stamp unlockWrite() metoduna parametre olarak geçilir.

modları
Üç tane mod var. Bunlar şöyle
- optimistic read stamp,
- read stamp,
- write stamp

Açıklaması şöyle.
This class also supports methods that conditionally provide conversions across the three modes. For example, method tryConvertToWriteLock(long) attempts to "upgrade" a mode, returning a valid write stamp if (1) already in writing mode (2) in reading mode and there are no other readers or (3) in optimistic mode and the lock is available. The forms of these methods are designed to help reduce some of the code bloat that otherwise occurs in retry-based designs.
optimistic read için açıklama şöyle. Normalde read lock varken write lock bekler. Ancak optimistic read stamp, write işlemi yapmak isteyen thread'i bloke edemez. Dolayısıyla write işlemi beklemeden gerçekleşir.
This mode can be thought of as an extremely weak version of a read-lock, that can be broken by a writer at any time. The use of optimistic read mode for short read-only code segments often reduces contention and improves throughput
Neden Lazım ?
Örnek
Elimizde şöyle bir kod olsun. Burada name listede varsa bile write lock  kullanmak zorundayız
private final ReadWriteLock LOCK = new ReentrantReadWriteLock();

public void addName(String name) {
   LOCK.writeLock().lock();
   try {
       if(!listOfNames.contains(name)) {
           listOfNames.add(name);
       }
   } finally {
       LOCK.writeLock().unlock();
   }
}
Bunu şu hale getirebiliriz
public void addName(String name) {
  long stamp = LOCK.readLock();
   try {
       if(!listOfNames.contains(name)) {
           long writeLock = LOCK.tryConvertToWriteLock(stamp);
           if(writeLock == 0) {
               throw new IllegalStateException();
           }
           listOfNames.add(name);
       }
   } finally {
       LOCK.unlock(stamp);
   }
}

reentrant Özelliği
Bu sınıf reentrant değildir. Açıklaması şöyle.
StampedLock is an alternative to using a ReadWriteLock. The main differences between StampedLock and ReentrantReadWriteLock are that:

- StampedLocks allow optimistic locking for read operations
- ReentrantLocks are reentrant (StampedLocks are not)
constructor
Şöyle yaparız.
StampedLock sl = new StampedLock();
readlock metodu
readLock() metodundan önce tryOptimisticRead() çağrısı yapılır ve bu çağrının sonucu validate() metodu ile kontrol edilir. Eğer validate başarısız ise yani 0 dönerse bu sefer readLock() çağrısı yapılır. Lock unlockRead() ile serbest bırakılır. Açıklaması şöyle.
The "possibly racy reads" is because, on the first loop, the thread has tried to optimistically obtain the read lock but it may have failed. If the lock is valid (validate), then the read values are safe and it proceeds to use them. Otherwise, the read values are not safe and the loop continues, now obtaining the read lock via the blocking readLock() method.
Örnek
Şöyle yaparız
class Point {
   private double x, y;
   private final StampedLock sl = new StampedLock();

  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);
   }
}
Örnek
Şöyle yaparız.
class Point {
  private double x, y;
  private final StampedLock sl = new StampedLock();
  // a read-only method
  // upgrade from optimistic read to read lock
  double distanceFromOrigin() {
    long stamp = sl.tryOptimisticRead();
    try {
      retryHoldingLock: for (;; stamp = sl.readLock()) {
        if (stamp == 0L)
          continue retryHoldingLock;
        // possibly racy reads
        double currentX = x;
        double currentY = y;
        if (!sl.validate(stamp))
          continue retryHoldingLock;
        return Math.hypot(currentX, currentY);
      }
    } finally {
      if (StampedLock.isReadLockStamp(stamp))
        sl.unlockRead(stamp);
    }
  }
}
tryOptimisticRead metodu
Açıklaması şöyle
An optimistic read lock is acquired by calling tryOptimisticRead() which always returns a stamp without blocking the current thread, no matter if the lock is actually available. If there's already a write lock active the returned stamp equals zero. You can always check if a stamp is valid by calling lock.validate(stamp).
Örnek
Şöyle yaparız.
long stamp = sl.tryOptimisticRead();
writeLock metodu
writeLock() çağrısı yapılır. Lock unlockWrite() ile serbest bırakılır. Açıklaması şöyle.

Örnek
Şöyle yaparız.
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);
    }
  }
 }