Java’da Thread Yönetimi ve Thread Durumları Nelerdir?

Java’da thread’ler farklı durumlarda bulunabilir ve bu durumlar thread’in yaşam döngüsünün bir parçasıdır. Bir thread’in yönetilmesi ve farklı durumlardaki geçişleri anlamak, Java’da concurrency (eşzamanlılık) ile uğraşırken kritik bir öneme sahiptir. Bu yazıda, Java’da thread yönetimi ve thread durumları üzerine detaylı bir inceleme yapacağız. Java’da thread’in çeşitli durumları (thread states) ve bu durumların ne anlama geldiği hakkında bilgi edineceğiz.

Thread’in Yaşam Döngüsü

Java’da bir thread, oluşturulmasından itibaren çeşitli durumlardan geçer. Bu durumlar, bir thread’in çalışma süresince belirli bir noktada ne yaptığını veya hangi aşamada olduğunu gösterir. Thread’ler beş ana durumda bulunabilir:

  • NEW (Yeni): Thread oluşturulmuş fakat henüz başlatılmamış durumda.
  • RUNNABLE (Çalışabilir): Thread çalışmaya hazır veya çalışıyor. CPU tarafından işlenmeyi bekliyor olabilir.
  • BLOCKED (Bloklanmış): Thread, bir kilidi (lock) elde etmek için bekliyor.BLOCKED (Bloklanmış): Thread, bir kilidi (lock) elde etmek için bekliyor.
  • WAITING (Bekliyor): Thread başka bir thread’in bir eylemi tamamlamasını bekliyor.
  • TIMED_WAITING (Zamanlı Bekliyor): Thread belirli bir süre boyunca beklemeye alınmış.
  • TERMINATED (Sonlanmış): Thread görevini tamamlamış ve çalışması bitmiş.

Bu durumları ve aralarındaki geçişleri daha iyi anlamak, thread’lerin doğru şekilde yönetilmesi için çok önemlidir.

1) NEW (Yeni)

Bir thread Thread sınıfının bir örneği oluşturularak yaratıldığında, fakat henüz start() metodu çağrılmadığında, thread NEW durumundadır.

Örnek:

Thread thread = new Thread(() -> {
    System.out.println("Thread çalışıyor");
});
System.out.println("Durum: " + thread.getState()); // NEW

Bu durumda thread oluşturulmuş ancak henüz çalışmaya başlamamıştır.

2) RUNNABLE (Çalışabilir)

start() metodu çağrıldıktan sonra thread RUNNABLE durumuna geçer. RUNNABLE durumda olan bir thread, CPU tarafından çalıştırılmayı bekler veya aktif olarak çalışıyordur. Java’da RUNNABLE durumu hem CPU tarafından çalıştırılmayı bekleyen hem de aktif çalışan thread’leri içerir.

Örnek:

Thread thread = new Thread(() -> {
    System.out.println("Thread çalışıyor...");
});
thread.start();
System.out.println("Durum: " + thread.getState()); // RUNNABLE

start() metodunun çağrılması ile thread, çalışmaya başlamak için sıraya girer ve RUNNABLE duruma geçer.

3) BLOCKED (Bloklanmış)

Bir thread, ortak bir kaynağı (örneğin bir metod veya nesne) kilitlemek için başka bir thread’in kilidi serbest bırakmasını beklerken BLOCKED duruma geçer. Genellikle synchronized anahtar kelimesi ile korunan bir kaynağa erişmeye çalışan thread’ler bloklanabilir.

Örnek:

public class Main {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 1 kilidi aldı");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread 2 kilidi aldı");
            }
        });

        thread1.start();
        thread2.start();
    }
}

Bu örnekte, thread1 kilidi aldıktan sonra thread2, aynı kilidi serbest bırakana kadar BLOCKED durumda kalacaktır.

4) WAITING (Bekliyor)

Bir thread, başka bir thread’in bir işlemi tamamlamasını beklerken WAITING durumuna geçer. Bu duruma Object.wait() veya Thread.join() gibi yöntemler neden olabilir. WAITING durumu, belirli bir süre belirtilmeden, sınırsız olarak sürebilir.

Örnek:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("Thread 1 tamamlandı");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                thread1.join(); // thread1'in tamamlanmasını bekle
                System.out.println("Thread 2 çalışıyor");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
    }
}

Bu örnekte, thread2, thread1 tamamlanana kadar WAITING durumunda kalacaktır. join() metodu ile thread2, thread1 bitmeden çalışmaya başlamaz.

5) TIMED_WAITING (Zamanlı Bekliyor)

Bir thread belirli bir süre boyunca beklemeye alındığında TIMED_WAITING durumuna geçer. Bu duruma Thread.sleep(long millis), Object.wait(long timeout) veya Thread.join(long millis) gibi yöntemler neden olabilir.

Örnek:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(3000); // 3 saniye bekle
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
        Thread.sleep(1000); // thread'in durumu kontrol edilmeden önce 1 saniye bekle
        System.out.println("Durum: " + thread.getState()); // TIMED_WAITING
    }
}

Bu örnekte, thread 3 saniye boyunca bekletilir ve bu sırada durumu TIMED_WAITING olacaktır.

6) TERMINATED (Sonlanmış)

Bir thread, çalışmasını tamamladığında TERMINATED durumuna geçer. Bu durumda, thread ya normal bir şekilde tamamlanmış ya da bir hata nedeniyle sonlanmış olabilir.

Örnek:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("Thread çalışıyor...");
        });

        thread.start();
        thread.join(); // Thread'in bitmesini bekle
        System.out.println("Durum: " + thread.getState()); // TERMINATED
    }
}

Bu örnekte, thread görevini tamamladıktan sonra TERMINATED durumuna geçer.


Thread Durumları Arasındaki Geçişler

Bir thread, yaşam döngüsü boyunca bir durumdan diğerine geçiş yapar. Bu geçişler şu şekildedir:

  • NEWRUNNABLE: start() metodu çağrıldığında.
  • RUNNABLEBLOCKED: Bir kilit elde edilemediğinde.
  • RUNNABLEWAITING/TIMED_WAITING: wait(), join(), veya sleep() metodları çağrıldığında.
  • RUNNABLE/WAITINGTERMINATED: run() metodu sonlandığında veya bir istisna oluştuğunda.

Bu geçişleri anlamak, thread’lerin davranışını tahmin edebilmek ve thread yönetimini daha iyi yapabilmek için önemlidir.


Bu makalede, Java’da thread yönetimi ve thread state’leri detaylı bir şekilde ele aldık. Thread’lerin yaşam döngüsünde geçirdiği durumları, bu durumlar arasındaki geçişleri ve her bir duruma dair örnekleri inceledik. Bu bilgiler, çoklu iş parçacığı kullanımı ile çalışan Java geliştiricileri için kritik önem taşımaktadır.