1 ay kadar bir süreden sonra blogun ikinci yazısıyla ve 2026’nın ilk yazısıyla yeniden buradayım. Oldukça geniş bir kavram olan asenkron programlama için bu yazıyı bir giriş oluşturma amacıyla kaleme almak istedim.

Asenkron kavramı nedir?
Asenkron kavramını basitçe şöyle özetleyebiliriz:
“Bir işi başlatırım, o işin bitmesini beklemeden başka işlere devam ederim.
İş tamamlandığında kaldığım yerden devam ederim.”
Buradaki kritik nokta beklememek değil, beklerken meşgul olmamaktır.
Gerçek hayattan bir örnek
Bir restoranda sipariş verdiğimizi düşünelim. Garson siparişi alır ve mutfağa iletir; ancak yemek hazırlanırken masanın başında beklemez. Bu süre boyunca başka müşterilerle ilgilenir. Yemek hazır olduğunda tekrar masaya döner.
Garsonun yaptığı şey şudur: beklemeyi yönetmek.

Senkron iş için bir canlı örnek :
Senkron modele örnek vermek istersek, banka kuyruğunu düşünebiliriz.
Gişe görevlisi bir müşterinin işlemini gerçekleştirirken, sıradaki herkes bu işlemin bitmesini bekler. Görevli, mevcut müşterinin işlemi tamamlanmadan bir sonraki kişiden kimlik ya da evrak istemez.
Yani kuyruktaki herkes, en öndeki kişinin işinin bitmesine bağlıdır.

Peki asenkron programlama Java Spring’de neyi çözer?
Burada ilk akılda tutulması gereken ve bence en önemli nokta şudur:
Asenkron programlama bir teknik değil,
bir kaynak yönetimi stratejisidir.
Bir Spring Boot uygulamasında temel olarak üç kaynağımız var :
- CPU
- Memory
- Thread
Asenkron programlama konusunda doğrudan threadlerle ilgileniriz.
Thread gerçekte ne yapar?
Bir thread temelde iki durumda bulunur:
- CPU üzerinde aktif olarak çalışır
- I/O bekler (veritabanı, HTTP, disk, mesajlaşma sistemleri vb.)
Buradak kritik nokta şu :
Thread I/O beklerken CPU kullanmaz, fakat bekleme süresi boyunca kilitli kalır ve başka bir iş alamaz.
Bu yüzden prod ortamlarda sıklıkla şu tabloyu görürüz:
- CPU kullanımı düşük
- Sistem yavaş veya tıkalı
Spring Boot’un varsayılan modeli

Spring Boot varsayılan olarak:
1 request = 1 thread
modeliyle çalışır.
Bu yaklaşım aslında bize şunu sağlıyor:
- Basit
- Okunabilir
- Öğrenmesi kolaydır
Ancak I/O ağırlıklı sistemlerde yük altında ciddi verimsizlik ve çökmelere kapı aralıyor.
Basit bir örnek kod
Aşağıdaki endpoint’i ele alalım:
@GetMapping("/order/{id}")
public OrderDto getOrder(Long id) {
Order order = calculateAndHash(id); // CPU (~50 ms)
Payment payment = paymentClient.get(order); // HTTP (~300 ms)
Shipment shipment = shipmentClient.get(order); // HTTP (~400 ms)
return new OrderDto(order, payment, shipment);
}
Bu kodda:
calculateAndHashmetodu tamamen CPU-bound bir işlemdir.
Thread bu süre boyunca aktif olarak CPU üzerinde çalışır.- HTTP çağrıları da I/O bekleme içerir
Java thread açısından baktığımızda:
- Yaklaşık 50 ms aktif CPU çalışması vardır
- Yaklaşık 700 ms I/O bekleme süresi vardır
Yani thread’in:
%93’ü fiilen çalışmadan geçmesine rağmen
hala tahsisli ve meşguldür.
Basit bir kapasite hesabı
Tomcat thread pool’unun 200 olduğunu varsayalım.
Ortalama response süresi:
750 ms
Bu durumda saniyede işlenebilecek maksimum istek sayısı:
200 / 0.75 ≈ 266 request/sec
Bu sırada:
- CPU neredeyse boştur
- Ama sistem daha fazla isteği kabul edemez
Çünkü thread’ler beklemektedir.
Kritik soru: Thread neden bekliyor?

Çünkü sistem, başlatılan bir işin sonucuna
aynı akış içinde ihtiyaç duyar.
Bu da şu anlama gelir:
- İş tamamlanmadan ilerlenemez
- Thread beklemek zorunda kalır
- Beklerken başka bir iş alamaz
Sonuç olarak:
Sistem CPU açısından boş,
ancak thread kapasitesi açısından doludur.
Senkron ve asenkron düşünce farkı
Bu noktada iki farklı yaklaşım ortaya çıkar:
Senkron düşünce
- Her adımın bir öncekini beklemesini zorunlu kılar
- Beklemeyi doğal kabul eder
Asenkron düşünce
- Zaman bağını gevşetmeyi hedefler
- Bekleme süresini verimli kullanmayı amaçlar
Multithreading = Asenkronluk yanılgısı
Yaygın bir yanlış inanış şudur:
“Yeni thread açarsam asenkron olurum.”
Eğer kullanılan yapılar blocking ise:
- Daha fazla thread
- Daha fazla context switch
- Daha fazla memory tüketimi
elde edilir.
Asenkronluğun gücü:
“Az thread ile çok isteği verimli şekilde yönetebilmekten gelir.”
Message Brokerlar tek başına yeterli değildir

Kafka veya benzeri mesajlaşma sistemlerini kullanmak,
uygulamanın otomatik olarak asenkron olduğu anlamına gelmez.
Mesajlaşma sistemleri:
- Sadece mesajı taşır
- Thread yönetimi ve blocking / non-blocking davranışlar
uygulama tarafında belirlenir
Tabii ki asenkron programlama her derde deva değil. Debug etmesi daha zor, akış takibi daha karmaşık. Bu, benim en sevmediğim ve hatta uzun süre asenkron programlamaya direnç göstermeme neden olan konulardan biri oldu.
Özellikle senkron ve üstten alta sıralı kod akışına alışık biri için; asenkron yapıların insanda sürekli olarak “kontrol bende değil” hissi uyandırdığını düşünüyorum.
Kod çalışıyor gibi, ama bir şeyler bir yerden bir yere “uçuyormuş” hissi veriyor.
Akışın tek bir call stack üzerinde ilerlememesi, debug sırasında zihinsel modeli ciddi şekilde zorlayan bir durum.

Sonuca Gelirsek ..
Asenkron programlama kod yazma tekniği değil veya bir tür performans hilesi değil. Burada beklemeyi yönetebilmek kritik nokta.
Bu yazımda asenkronluğu nasıl uygulayacağımızdan özellikle bahsetmedim. Çünkü önce konsept için basit bir giriş yapmak istedim. Yazıda asenkronluğu nasıl uygulayacağımızı değinmeden buna neden buna ihtiyaç duyduğumuzu ele almaya çalıştım.
Bir sonraki yazıda ele alacağım konu “Thread Lifecycle, Context Switch ve Thread Memory Hakkında” , görüşmek üzere 🙂
Bir yanıt yazın