9 Haziran 2016 Perşembe

AtomicReference Sınıfı

Giriş
Şu satırı dahil ederiz.
import java.util.concurrent.atomic.AtomicReference;
Açıklaması şöyle.
The class AtomicReference wraps another class to enrich a variable with atomic update functionality.
Açıklaması şöyle.
Provides atomic operations for reference variables. It has the same methods as atomic boolean, but provides us ability to make atomic operations on our own class.
constructor

Şöyle yaparız.
AtomicReference<Foo> result = new AtomicReference<Foo>();
compareAndSet metodu - expectedValue + newValue
Her zaman döngü içinde kullanılır. Açıklaması şöyle. Eğer birinci parametre yani expected value ile nesnenin şimdiki değeri aynıysa, ikinci parametrenin yani new value değerini atar ve true döner.
The compareAndSet method takes two parameters, the expected current value and the new value. The method atomically checks if the current value equals the expected value. If yes, then the method updates the value to the new value and returns true. If not, the method leaves the current value unchanged and returns false.
Açıklaması şöyle.
Using volatile variables leads to race conditions since specific thread interleavings for a thread overwrites the computation of other threads. By using the compareAndSet method from the class AtomicReference, we can circumvent this race condition. We atomically check if the current value is still the same as when we started the computation. If yes, we can safely update the current value. Otherwise, we need to recalculate the new value with the changed current value.
Örnek
Şöyle yaparız
AtomicReference<State> state = new AtomicReference<State>(new State());

public void update() {

  State current = state.get();
  State newValue = current.update();

  while( ! state.compareAndSet(current , newValue ) ) {//başkası değiştirdiyse tekrarla
    current = state.get(); //Yeni değeri al
    newValue = current.update();
  }
}
Örnek
Şöyle yaparız. Burada BigInteger değeri atomic olarak artırılıyor
public class AtomicBigInteger {

  AtomicReference<BigInteger> valueHolder = new AtomicReference<>();

  public AtomicBigInteger(BigInteger bigInteger) {
    valueHolder.set(bigInteger);
  }

  public BigInteger incrementAndGet() {
    for (; ; ) {
      BigInteger current = valueHolder.get();
      BigInteger next = current.add(BigInteger.ONE);
      if (valueHolder.compareAndSet(current, next)) {
        return next;
      }
    }
  }
}
Örnek
Şöyle yaparız. Burada bir reentrant lock gerçekleştirimi var.
public class ReentrantSpinLock {
  private AtomicReference<Thread> cas = new AtomicReference<>();
  private int count;
  public void lock() {
    Thread current = Thread.currentThread();
    //If the current thread has acquired the lock, 
    //the number of threads is increased by one, and then returns
    if (current == cas.get()) { 
      count++;
      return;
    }
    //If the lock is not acquired, it can be spun through CAS
    while (!cas.compareAndSet(null, current)) {
      // DO nothing
    }
  }
  public void unlock() {
    Thread cur = Thread.currentThread();
    if (cur == cas.get()) {
      //If it is greater than 0, it means that the current thread has acquired the lock 
      //many times /and releasing the lock is simulated by count subtraction
      if (count > 0) {
        count--;
      } else {
        //If count = = 0, the lock can be released, so that the number of times to acquire
        //the lock is consistent with the number of times to release the lock.
        cas.compareAndSet(cur, null);
      }
    }
  }
}
Örnek
Şöyle yaparız. Burada deserialize işleminde consistency tercih ediliyor. Bu yüzden while() ile bekleniyor.
public class ConcurrentDeserializer {

  AtomicReference<byte[]> serializedBlob = new AtomicReference<>();

  AtomicBoolean waitDeserialization = new AtomicBoolean(false);

  AtomicReference<Object> deserializedBlob = new AtomicReference<>();

  public void setSerialized(final byte[] blob) {
    serializedBlob.set(blob);
  }

  public Object getDeserialized() {
    while (waitDeserialization.get()) {
    }

    //New data has arrived
    if (serializedBlob.get() != null) {
      //If thread can get the flag, perform deserialization,
      //otherwise just return the latest deserialized object
      if (waitDeserialization.compareAndSet(false, true)) {
        //Deserialize the latest data.
        byte[] blob = serializedBlob.get();
        Object obj = deserialize(blob);
        deserializedBlob.set(obj);

       //If no new data has arrived, set blob to null so that, another deserialization 
       //does not happen
       serializedBlob.compareAndSet(blob, null);

       //Send "go" to waiting threads
       waitDeserialization.set(false);
     }
   }
   return deserializedBlob.get();
  }

  private Object deserialize(byte[] blob) {
    return new String(blob);
  }

  private Object deserialize(byte[] blob) {
    return new String(blob);
  }
}
get metodu
Şöyle yaparız.
result.get();
Şöyle yaparız.
if (result.get() == null) {...}
getAndSet metodu
Örnek
Şöyle yaparız
AtomicReference<Person> atomicPerson = new AtomicReference<>(new Person("Alice"));

// Get and Set a new person
Person previousPerson = atomicPerson.getAndSet(new Person("David"));
System.out.println("Previous Person: " + previousPerson.getName());
System.out.println("Updated Person: " + atomicPerson.get().getName());
set metodu
Şöyle yaparız.
result.set(new Foo());


Hiç yorum yok:

Yorum Gönder