8 Kasım 2019 Cuma

Thread Safety

Bu yazimda Thread Safety konusunu ele alacagim. Mutation diye bir kavram var ne oldugunu biliyor muyuz ? Tek tek gidelim.

Mutable ve Immutable degiskenlerden bahsedelim. Mutable degisebilen demektir. Immutable ise degismez. Ornegin javadaki String classina bakalim.

String ornek = "Gamze";
ornek.toUpperCase();
System.out.println(ornek);

Sonucun ne olmasini bekliyoruz ? Sonuc Gamze dir. Neden diyecek olursak String immutable yani degismez oldugu icin. Eger degistirmek istersek yeni bir degiskene atayarak kullanmamiz lazim.

Thread konusuna gececek olursak eger ayni anda birden fazla islem gerceklestirmek istiyorsak bunu threadler yardimiyla yapabiliriz. Her bir threadle farkli bir is yapip, birden fazla threadle isimizi gerceklestirebiliriz.

Simdi bu iki konuyu birbiriyle baglayalim. Bir program yazarken amacimiz datalari degistirmektir, cunku istedigimiz islemi bu sekilde yapabiliriz. Yani mutation bizim icin onemli. Multithreading de bizim icin onemli ki birden fazla isi ayni anda yapabilelim.

Bir tane shared datamiz oldugunu ve birden fazla thread in buna erismeye calistigini dusunelim. Tabiki get etmeye calisirken sorun yok. Ama bu threadler datayi degistirmeye calistigi anda problem ortaya cikar. Buna Race Condition denir. Java da immutable objeler thread safe dir. Zaten kimse degistiremedigi icin sorun olusturmazlar.

public class ThreadExample {
 static class Counter {
  int count;  
  public void increment() {
   count ++;
  }
 } 
 public static void main(String[] args) {
  Counter c = new Counter();
  for(int i=0; i< 2000; i++) {
   c.increment();
  }  
  System.out.println(c.count);
 }}
Ornegimizde gordugumuz gibi increment adinda bir fonksiyonumuz var. Datamizi degistirmeye calisiyor. 2000 defa datayi degistirmeye calisalim. Sonuc olarak ne bekliyoruz. 2000 

Burda bir sorun yok. Simdi burada multiple thread kullanmaya calisalim. 2 thread kullanalim ve ayni sonucu yani 2000 i elde etmeye calisalim. Bu durumda ne olmali. 1. thread i 1000, 2.threadi 1000 defa cagirdigimizda 2000 cikmasini bekleriz.

 public static void main(String[] args) throws InterruptedException {
  Counter c = new Counter();
  Thread thread1 = new Thread(new Runnable() {   
   @Override
   public void run() {
    for(int i=0; i< 1000; i++) {
     c.increment();
    }
   }
  });  
  Thread thread2 = new Thread(new Runnable() {   
   @Override
   public void run() {
    for(int i=0; i< 1000; i++) {
     c.increment();
    }
   }
  });  
  thread1.start();
  thread2.start();  
  // join() cagirmamizin sebebi bu 2 thread bitene kadar beklemesi icin
  thread1.join();
  thread2.join();  
  System.out.println(c.count);
 }


2 threadimiz var ve her biri 1000 defa calisiyor. 2000 sonucunu gormeyi bekliyoruz, ama her calistirdigimizda sonuc degisiyor. 2000 de gelebiliyor 1550 de 1200 de.


Bunun sebebi datamizi degistiren increment methodunun thread safe olmamasi. Ayni anda count degiskenine 2 thread de ulasmaya calisiyor ve degeri degistiriyor.

Bunu onlemek icin 2 yontem var.

1. Synchronized  Keyword

Increment methoduna sychronized eklersek ayni anda threadin datamiza erismesine ve degistirmesine izin vermez.

public synchronized void increment() {
 count ++;
}

Bu durumda surekli 2000 sonucunu elde edebiliriz.

2. Atomic Integer


AtomicInteger count = new AtomicInteger();
public synchronized void increment() {
 count.incrementAndGet();
}


Bu 2 yontemle thread safety e erisebiliriz.

Hiç yorum yok:

Yorum Gönder