Thread Lifecycle ve Yönetim
Önceki derste thread oluşturmayı ve başlatmayı gördük. Şimdi bir thread'in hayat hikayesini detaylıca inceleyeceğiz. Doğumdan ölüme kadar her aşamayı, thread'leri nasıl yöneteceğimizi ve kontrol edeceğimizi öğreneceğiz.
Thread Yaşam Döngüsü — Detaylı
Bir thread'in hayatını bir insanın iş gününe benzetebilirsin:
NEW → Sabah uyanmışsın ama evden çıkmamışsın (oluşturuldu ama başlamadı)
RUNNABLE → İşe gitmek için hazırsın, otobüs bekliyorsun (CPU bekliyor)
RUNNING → Masanda oturmuş çalışıyorsun (CPU üzerinde çalışıyor)
BLOCKED → Toplantı odası dolu, kapıda bekliyorsun (lock bekliyor)
WAITING → Patrondan onay bekliyorsun, süre belirsiz (süresiz bekleme)
TIMED_WAITING → 15 dk kahve molası verdin (süreli bekleme)
TERMINATED → İş günü bitti, eve gittin (thread sonlandı)
start()
NEW ─────────→ RUNNABLE ←──────→ RUNNING
↑ │
│ ┌───────────┼───────────┐
│ ↓ ↓ ↓
│ BLOCKED WAITING TIMED_WAITING
│ │ │ │
└──────┘───────────┘───────────┘
│
↓
TERMINATEDHer Durumu Gözlemle
public class ThreadDurumlari {
public static void main(String[] args) throws Exception {
Object lock = new Object();
Thread t = new Thread(() -> {
// RUNNABLE → synchronized bloğuna girmeye çalışır
synchronized (lock) {
try {
lock.wait(); // WAITING durumuna geçer
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "TestThread");
System.out.println("Oluşturuldu: " + t.getState()); // NEW
t.start();
Thread.sleep(50);
System.out.println("Başlatıldı: " + t.getState()); // WAITING
synchronized (lock) {
lock.notify(); // Thread'i uyandır
}
t.join();
System.out.println("Bitti: " + t.getState()); // TERMINATED
}
}BLOCKED Durumu
Thread, synchronized blok veya metoda girmeye çalışıp monitör kilidi (monitor lock) başka bir thread tarafından tutuluyorsa BLOCKED durumuna geçer.
Object kilit = new Object();
Thread t1 = new Thread(() -> {
synchronized (kilit) {
System.out.println("t1 kilidi aldı");
try {
Thread.sleep(5000); // 5 saniye kilidi tutar
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println("t2 kilidi almaya çalışıyor...");
synchronized (kilit) { // t1 kilidi bırakana kadar BLOCKED
System.out.println("t2 kilidi aldı!");
}
}, "t2");
t1.start();
Thread.sleep(100); // t1'in kilidi almasını bekle
t2.start();
Thread.sleep(100);
System.out.println("t2 durumu: " + t2.getState()); // BLOCKEDWAITING ve TIMED_WAITING
WAITING — Süresiz Bekleme
Object.wait(), Thread.join() veya LockSupport.park() ile girilir.
Thread t = new Thread(() -> {
synchronized (kilit) {
try {
kilit.wait(); // Süresiz bekle — birisi notify edene kadar
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});TIMED_WAITING — Süreli Bekleme
Thread.sleep(ms), Object.wait(ms), Thread.join(ms) ile girilir.
Thread t = new Thread(() -> {
try {
Thread.sleep(3000); // 3 saniye — TIMED_WAITING
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});Thread Priority — Öncelik
Her thread'in bir öncelik değeri var (1-10). Yüksek öncelikli thread'ler daha fazla CPU zamanı alma eğiliminde — ama garanti değil.
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Düşük: " + i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Yüksek: " + i);
}
});
t1.setPriority(Thread.MIN_PRIORITY); // 1
t2.setPriority(Thread.MAX_PRIORITY); // 10
System.out.println("Varsayılan: " + Thread.NORM_PRIORITY); // 5
t1.start();
t2.start();| Sabit | Değer |
|---|---|
Thread.MIN_PRIORITY | 1 |
Thread.NORM_PRIORITY | 5 (varsayılan) |
Thread.MAX_PRIORITY | 10 |
⚠️ Thread priority'ye güvenme! İşletim sistemi ve JVM implementasyonuna göre davranış değişir. Bazı OS'ler priority'yi tamamen görmezden gelir. Kod mantığını priority'ye bağımlı yapma.
Daemon Threads — Arka Plan Thread'leri
İki tür thread var:
User thread (normal) — JVM, tüm user thread'ler bitene kadar çalışır
Daemon thread — Arka plan servisi, tüm user thread'ler bitince otomatik sonlanır
Daemon thread'ler, temizlik, log yazma, garbage collection gibi arka plan görevleri için kullanılır.
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Daemon çalışıyor...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
});
daemon.setDaemon(true); // start()'tan ÖNCE ayarlanmalı!
daemon.start();
// Main thread 3 saniye sonra biter
Thread.sleep(3000);
System.out.println("Main bitti");
// Daemon thread otomatik sonlanır — program kapanır// Daemon mı kontrol et
System.out.println(daemon.isDaemon()); // true
// Main thread her zaman user thread'dir
System.out.println(Thread.currentThread().isDaemon()); // false💡 Daemon thread kuralları: -
setDaemon(true)start()'tan önce çağrılmalı — yoksaIllegalThreadStateException- Daemon thread'den oluşturulan thread'ler de daemon olur - Daemon thread'de kritik iş yapma — JVM kapanınca aniden sonlanır, finally blokları bile çalışmayabilir
Daemon Thread Kullanım Örneği
public class OtomatikKayit {
public static void main(String[] args) throws InterruptedException {
List<String> loglar = new ArrayList<>();
// Arka planda her 2 saniyede logları "diske yazan" daemon
Thread logYazici = new Thread(() -> {
while (true) {
try {
Thread.sleep(2000);
if (!loglar.isEmpty()) {
System.out.println("[DAEMON] " + loglar.size() + " log yazıldı");
loglar.clear();
}
} catch (InterruptedException e) {
break;
}
}
}, "LogYazici");
logYazici.setDaemon(true);
logYazici.start();
// Ana iş
for (int i = 0; i < 10; i++) {
loglar.add("Log #" + i);
Thread.sleep(500);
}
System.out.println("Ana iş bitti");
// Program kapanır, daemon da sonlanır
}
}Thread Interrupt — Thread'i Kesmek
Bir thread'i dışarıdan durdurmak istediğinde interrupt kullanılır. Ama dikkat: interrupt, thread'i zorla durdurmaz — "dur artık" sinyali gönderir. Thread'in bunu kontrol edip kendini durdurması gerekir.
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Çalışıyorum...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Uyandırıldım, duruyorum.");
Thread.currentThread().interrupt(); // Bayrağı tekrar set et
break;
}
}
System.out.println("Thread sonlandı.");
}, "Isci");
t.start();
Thread.sleep(3500);
t.interrupt(); // "Dur" sinyali gönderÇıktı:
Çalışıyorum...
Çalışıyorum...
Çalışıyorum...
Uyandırıldım, duruyorum.
Thread sonlandı.Interrupt Mekanizması
İki durum var:
1. Thread bloklanmış durumda ise (sleep, wait, join): InterruptedException fırlatılır ve interrupt bayrağı temizlenir.
2. Thread çalışıyor durumda ise: Sadece interrupt bayrağı set edilir. Thread kontrol etmezse hiçbir şey olmaz.
// Çalışan thread — bayrağı kontrol etmeli
Thread t = new Thread(() -> {
long toplam = 0;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupt algılandı, duruyorum.");
return;
}
toplam += i;
}
});⚠️ `Thread.stop()` kullanma! Deprecated ve tehlikeli.
stop()thread'i aniden öldürür, kilit açılmaz, veri bozulabilir. Her zamaninterrupt()+ cooperative shutdown kullan.
InterruptedException Yakalama
// YANLIŞ — interrupt'ı yutma!
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Hiçbir şey yapma — KÖTÜ!
}
// DOĞRU — ya yeniden fırlat ya da bayrağı koru
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Bayrağı tekrar set et
return; // veya break
}Thread.yield() — CPU'yu Bırak
yield(), mevcut thread'in CPU'yu bırakıp diğer thread'lere şans vermesini önerir. Garanti değil.
Thread.yield(); // "Ben biraz bekleyeyim, başkaları çalışsın"Pratikte nadiren kullanılır. JVM ve OS zaten thread'leri iyi yönetir.
Thread Bilgileri
Thread t = Thread.currentThread();
System.out.println("İsim: " + t.getName()); // main
System.out.println("ID: " + t.getId()); // 1
System.out.println("Öncelik: " + t.getPriority()); // 5
System.out.println("Durum: " + t.getState()); // RUNNABLE
System.out.println("Daemon: " + t.isDaemon()); // false
System.out.println("Hayatta: " + t.isAlive()); // true
System.out.println("Grup: " + t.getThreadGroup()); // java.lang.ThreadGroup[...]
// Aktif thread sayısı
System.out.println("Aktif thread: " + Thread.activeCount());Pratik Örnek — Graceful Shutdown
Gerçek uygulamalarda thread'leri düzgün kapatmak önemli:
public class BackgroundService {
private volatile boolean running = true; // volatile önemli!
private Thread workerThread;
public void start() {
workerThread = new Thread(() -> {
System.out.println("Servis başladı.");
while (running) {
try {
// İş yap
System.out.println("İşlem yapılıyor...");
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println("Servis temiz şekilde kapandı.");
}, "BackgroundService");
workerThread.start();
}
public void stop() throws InterruptedException {
System.out.println("Kapatma sinyali gönderildi...");
running = false;
workerThread.interrupt();
workerThread.join(5000); // Max 5 saniye bekle
if (workerThread.isAlive()) {
System.out.println("UYARI: Thread hâlâ çalışıyor!");
}
}
}BackgroundService servis = new BackgroundService();
servis.start();
Thread.sleep(5000); // 5 saniye çalışsın
servis.stop();Çıktı:
Servis başladı.
İşlem yapılıyor...
İşlem yapılıyor...
İşlem yapılıyor...
İşlem yapılıyor...
İşlem yapılıyor...
Kapatma sinyali gönderildi...
Servis temiz şekilde kapandı.JVM Shutdown Hook
Program kapanırken temizlik yapmak için shutdown hook ekleyebilirsin:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Program kapanıyor, temizlik yapılıyor...");
// Dosyaları kapat, bağlantıları kes, vs.
}, "ShutdownHook"));Shutdown hook, JVM kapanırken çalışır: normal çıkış, System.exit(), CTRL+C, hatta kill sinyali. Ama kill -9 veya güç kesintisinde çalışmaz.
Thread Grupları (Kısa Bilgi)
Thread'ler gruplar halinde organize edilebilir:
ThreadGroup grup = new ThreadGroup("İşçiler");
Thread t1 = new Thread(grup, () -> { /* iş */ }, "İşçi-1");
Thread t2 = new Thread(grup, () -> { /* iş */ }, "İşçi-2");
t1.start();
t2.start();
System.out.println("Gruptaki aktif thread: " + grup.activeCount());
grup.list(); // Grup bilgilerini yazdırPratikte thread grupları yerine ExecutorService (thread pool) tercih edilir. Bir sonraki konularda göreceğiz.
Özet
Thread yaşam döngüsü: NEW → RUNNABLE → RUNNING → BLOCKED/WAITING/TIMED_WAITING → TERMINATED
Priority (1-10) thread'e öncelik verir ama davranış garanti değil — koda bağımlı yapma
Daemon thread arka plan servisidir, tüm user thread'ler bitince otomatik sonlanır
interrupt() thread'e "dur" sinyali gönderir — cooperative shutdown,
stop()kullanmavolatile flag veya interrupt ile graceful shutdown sağla
Thread bilgileri:
getName(),getState(),isAlive(),isDaemon()ile sorgulanır
AI Asistan
Sorularını yanıtlamaya hazır