27 Temmuz 2022 Çarşamba

Happens-Before İlişkisi

Giriş 
Açıklaması şöyle
JVM can change the order of the instructions which won't make any significant changes in the program. 
Happens-Before Nedir
Açıklaması şöyle. Bir açıklama da burada.
If between two threads, we installed the happens-before relation, then the second (ending thread) will see all changes that happened in the first thread. Therefore, the second thread execution will be similar to a single thread application.
Happens-Before İlişkisi Nasıl Kurulur
1. volatile kelimesi kullanılır
2. final kelimesi kullanılır
2. Synchronized Monitor kullanılır
3. Thread start() ve join() çağrılarında otomatik kurulur
Yani başlayan thread, parent thread içindeki değişiklikleri görür. Child thread bitince de parent thread join() ile beklediği için, child thread tarafından yapılan değişiklikleri görür

final Anahtar Kelimesi
Örnek - Yanlış Kod
class Example {
final int foo; Example() { foo = 42; } static Example instance; static void threadOne() { instance = new Example(); // Look at two steps below, they depict `new Example()` //instance = <allocate space in Heap: Example>; // instance.<init>(); } static void threadTwo() { if (instance != null) { assert instance.foo == 42; } } }
Açıklaması şöyle
1. First thread starts initialization. First step of initialization happens
2. Second thread checks the object for being not null . Sees that it is not -> grabs it. But it isn’t fully initialized yet. => Error prone as second step of initialization hasn’t ended in the first thread.

=> we have only partial happens-before working here as we didn’t get the full object.

Solution — use final keyword.

final field makes variable freeze — JVM isn’t allowed to publish an instance to another thread before setting the field to the value(s) it receives in the constructor.
Synchronized Monitor
Örnek
Açıklaması şöyle
... when the first thread updates the value and releases the lock, then in the second thread when the lock is acquired, the value also gets updated due to the happened-before relation. This rule applied to all locks from java.util.concurrent that use a Java monitor under the hood.  
Şöyle yaparız
private static final Object Lock = new Object();

public class Foo {
  //Volatile gerekli değil ancak kullanmakta fayda var
  volatile int x;
  volatile in y;
}

final Foo foo = new Foo ();
Thread t1 = new Thread(()-> {
  synchronized(Lock) {
    foo.x = 1;
    foo.y = 1;
    Lock.notifyAll();
  }
});

Thread t2 = new Thread(()-> {
  synchronized(Lock) {
    while(foo.x == 0) {
      try {
        Lock.wait();
      } catch (InterruptedException ignored) {}
    }  
  }
  System.out.println(foo.y + foo.x);
});

t1.start();
t2.start();
Parent Thread
Örnek
Şöyle yaparız
lass ThreadStart {

  int foo = 0;
  
  void threadStart() {
    foo = 40;
    new Thread() {
      @Override
      public void run() {
         assert foo == 40;
      }
    }.start();
  }
}
Açıklaması şöyle
Thread 1 starts thread 2 -> thread 2 is guaranteed to see all the data from thread 1
Thread 1 joins thread 2 -> thread 1 sees all data from thread 2 (of the joined thread)



Hiç yorum yok:

Yorum Gönder