14 Mart 2015 Cumartesi

Volatile Kullanımı

     Günümüzde yazdığımız uygulamalar, programlar genellikle çok çekirdekli işlemciye sahip olan cihazlar üzerinde çalışmaktadır. Yazdığımız uygulamanın daha etkili ve performanslı bir şekilde çalışmasını sağlamak için çok çekirdekli işlemcilerin bizlere sunduğu imkanlardan faydalanmamız gerekir.

     Thread'lerin bizlere sunduğu avantajlar kadar, bir o kadar da dikkat etmemiz gereken yerler vardır ki yazdığımız kod beklemediğimiz bir hata vermesin.

     Volatile kullanımı ile değişkenimizin cihazın main-memory yani ram'inde saklanacağını garanti altına almış oluruz. Bunun bize faydası ne olacak diye düşünebilirsiniz. Java'da yaratılan değişkenler performansı arttırmak için işlemci cache belleğinde değişikliğe uğrar. Bu da demek oluyor farklı cache'lerde farklı işlemler yapılabilir. Bu duruma örnek verecek olursak ;

     4 çekirdekli bir bilgisayarınız olduğunu varsayın ve oluşturduğunuz bir değişken farklı thread'ler tarafından erişime açık. Herhangi bir thread bu değişken üzerinde değişiklik yaptığında diğer thread'in bu değişikliğin farkında olması için volatile sözcüğünü kullanarak yapılacak tüm değişikliklerin ram üzerinde yapılmasını garanti altına almış oluruz. Bunu bir şekil üzerinde göstermek gerekirse.

Thread 1 -> CPU 1 Cache -> Main Memory (RAM)

Thread 2 -> CPU 2 Cache -> Main Memory (RAM)

-X adında bir integer değişkenimiz olsun ve ilk değeri 3 olsun.

-Thread 1 X'i ram'den okusun ve değerini 5 arttırsın. X'in yeni değeri 8 ancak ram'e yazılmadığını düşünelim. Çünkü bu arttırma işlemi 1. cache bellekte gerçekleşmektedir.

-Thread 2 X'i ram'den okuduğunda X'i 8 değil 3 olarak okuyacaktır. Çünkü Thread1 X'in yeni değerini ram'e yazmamıştır. Thread2 de X'in değerini 1 azaltsın ve değerini 2 yapsın. Şu an elimizde 3 farklı X değeri var. İlki ram'de bulunan X=3, diğer değerimiz Thread1'de bulunan X=8, ve son olarak da Thread2'de bulunan X=2 değerimiz.

     Bu gibi sorunlarla karşılaşmamak için "volatile" kullanılır. Eğer yukarıdaki durumda volatile kullanılsaydı X değeri Thread1 tarafından değiştirildiğinde bu yeni değer CPU1 cache belleğe değil ram'e yazılacaktı ve Thread2 X değerini okuduğunda X'i 3 olarak değil 8 olarak yani bizim bekledğimiz şekilde okuyacaktı.

     Volatile kullanımıyla farklı thread'ler tarafından değişken değerinin değişimini garanti altına olmuş oluyor muyuz diye düşünüebilirsiniz. Cevap is hayır :) Bu iki thread aynı zamanda değişkene erişmiş ve değerini farklı şekilde değiştirmiş olabilir. Bu durumda ise "synchronized" kullanarak okuma ve yazmanın atomik olmasını garanti altına almamız gerekmektedir.

Bol thread'li az bug'lı günler :)


2 yorum:

  1. Çok yararlı oldu teşekkürler :) Ayrıca metodlarda ve ya blok olarak synchronized kullanımı ve AtomicInteger gibi değişkenleri de tanıtabilir misiniz?

    public synchronized void add(int value){
    this.count += value;
    }

    synchronized(this){
    this.count += value;
    }

    private static AtomicInteger counter = new AtomicInteger(0);

    YanıtlaSil