Java’da Multithreading – Bölüm 11: Semaforlar

Semaforlar (Semaphores) -genelde- bir kaynağa erişimi kontrol etmek için kullanılan sayaçlardır. Kilit mekanizmaları gibi threadlerin senkronizasyonu için kullanılırlar fakat kilitlerden farklı olarak bağımsız threadler tarafından serbest bırakılabilirler (release).

HATIRLATMA! Bir thread tarafından elde edilmiş kilidi başka bir thread serbest bırakmaya kalktığında ”IllegalMonitorStateException” istisnası fırlatılır.

Örneğin programımızın bir sunucuya eş zamanlı isteklerde bulunması, ancak programımızdan o sunucuya eş zamanlı maksimum üç bağlantı olmasını istiyoruz. Tam da semaforlarla çözülebilecek bir durum. Kısıtlı kaynağımız “bağlantı sayısı”, üst sınır değeri ise “3”. Öyleyse 3 izinli (permit) bir semafor işimizi görecektir.

“java.util.concurrent.Semaphore” sınıfı kurucusu “permit” (izin) adlı bir parametre almaktadır. Bu değer ilgili kısıtın üst sınır değerini ifade eder. Örneğimiz için ifade edecek olursak, her bir thread bağlantı oluşturdukça semaforun “acquire()” (elde et) metodu ile semafordan bir izin alacaktır. İki thread daha bağlantı oluşturduğunda izin değeri “0” olacağından yeni bir thread izin istediğinde verilecek izin kalmadığından yeni threadler bekletilecektir. Ta ki önceki threadler işlerini bitirip -semaforun ”release()” metodunu kullanarak- aldıkları izni iade edene kadar.

Örnek programımız sunucu bağlantısı kurmaya çalışan 10 adet threadi oluşturup başlatan bir “main” metodu ve kontrollü bir şekilde sunucu bağlantılarını gerçekleştiren bir “Connection” sınıfından meydana gelmekte:

public class Application {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {
                try {
                    Connection.getInstance().connect();
                } catch (InterruptedException e) {
                }
            });
        }

        executorService.shutdown();
    }

}

“Connection” sınıfı:

public class Connection {

    private static Connection instance = new Connection();

    private int connectionCount = 0;

    private Semaphore semaphore = new Semaphore(3);

    private Connection() {
    }

    public static Connection getInstance() {
        return instance;
    }

    public void connect() throws InterruptedException {
        semaphore.acquire();

        try {
            doConnect();
        } finally {
            semaphore.release();
        }
    }

    private void doConnect() throws InterruptedException {
        synchronized (this) {
            connectionCount++;
            System.out.println("Bağlantı sayısı: " + connectionCount);
        }

        Thread.sleep(1000);

        synchronized (this) {
            connectionCount--;
        }
    }

}

“main” metodu bir thread havuzu oluşturarak içerisine aynı işi (sunucu bağlantısı kurmak) gerçekleştiren 10 adet thread ekler. Her biri “Connection” sınıfının “singleton” örneğinin “connect()” metodunu çağırmaktadır.

“connect()” metodunun başında “acquire()” metodu ile o thread için izin istenir. Eğer sayaç sıfıra ulaşmamışsa izin verilir ve bağlantı gerçekleştirilir. Bağlantı gerçekleştikten sonra alınan izin geri iade edilmelidir. Bunun için semaforun “release()” metodu kullanılır. Bağlantı sırasında hata alınması ihtimaline karşı try-finally bloğu kullanmak yerinde bir pratik olacaktır.

Programı çalıştırdığımızda çıktı aşağıdakine benzer şekilde olur:

Bağlantı sayısı: 1
Bağlantı sayısı: 2
Bağlantı sayısı: 3
Bağlantı sayısı: 1
Bağlantı sayısı: 2
Bağlantı sayısı: 3
Bağlantı sayısı: 3
Bağlantı sayısı: 2
Bağlantı sayısı: 3
Bağlantı sayısı: 2

İlk başta 3 bağlantı hemen kurulur. Fakat sonraki bağlantılar için önceki bağlantıların sonlanması, alınmış izinleri geri iade edilmesi gerekir. Semaforu oluştururken belirttiğimiz maksimum izin kısıtı (permit) sayesinde eş zamanlı bağlantı sayısı 3’ten fazla olamaz.

“Semaphore”un -boolean tipinde- ikinci bir parametre alan bir kurucusu daha mevcuttur. “fair” (adil) adlı bu “boolean” parametrenin değerinin “true” olması halinde izinlerin ilk giren ilk çıkar (first-in first-out) kuralıyla verileceği garanti edilir. Yani “acquire()” metodunu çağırarak izin isteyen bir threadin izni alan ilk thread olmasını garanti edilir. Performans gerekçeleriyle “fair” parametresinin varsayılan değeri “false”tur.

Reklamlar

Bir Yorum Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Connecting to %s