Java 21 (Eylül 2023) — LTS — YENİ KURUMSAL STANDART
| Özellik | Değer | |---|---| | Sürüm | Java 21 (JDK 21) | | Çıkış Tarihi | 19 Eylül 2023 | | Destek Türü | LTS (Long-Term Support) — UZUN VADELİ DESTEK | | LTS mı? | EVET. Java 8, 11, 17'den sonraki en yeni LTS. | |…
Java 21 (Eylül 2023) — LTS — YENİ KURUMSAL STANDART
Sürüm Bilgileri
| Özellik | Değer |
|---|---|
| Sürüm | Java 21 (JDK 21) |
| Çıkış Tarihi | 19 Eylül 2023 |
| Destek Türü | LTS (Long-Term Support) — UZUN VADELİ DESTEK |
| LTS mı? | EVET. Java 8, 11, 17'den sonraki en yeni LTS. |
| Destek Süresi | Tipik olarak 8+ yıl (sağlayıcıya göre genişletilmiş destek dahil) |
| Önceki LTS | Java 17 (Eylül 2021) |
| Sonraki LTS | Java 25 (Eylül 2025) |
| JEP Sayısı | 15 JEP |
NEDEN JAVA 21 YENİ KURUMSAL STANDART? (GÜÇLÜ VURGU)
Java 21, sadece bir başka sürüm değil; 2024-2028 arası kurumsal Java'nın yeni temel hattıdır. İşte nedenleri:
1. LTS = Uzun Vadeli Destek
Kurumlar üretim sistemlerini ara (feature) sürümlere kuramaz; çünkü onların desteği yalnızca 6 ay sürer. Java 21 LTS, yıllarca güvenlik yaması ve destek alacaktır. Java 8 ve Java 11'den göç eden devasa kod tabanlarının hedefi artık Java 21'dir (Java 17 yerine bile doğrudan 21 tercih edilmektedir, çünkü 21 daha fazla olgun özellik içerir).
2. Virtual Threads (Project Loom) KALICI
Bu, son 20 yılın en büyük JVM eşzamanlılık devrimidir. Yıllardır preview'de olan virtual threads ilk kez Java 21'de kalıcı oldu. Bu, sunucu tarafı Java'yı yeniden tanımlar: basit, bloklayıcı kod yazarak milyonlarca eşzamanlı bağlantıyı kaldırabilirsiniz. Reaktif programlamanın (Reactor, RxJava) karmaşıklığına çoğu senaryoda artık gerek kalmaz.
3. Modern Dil Özellikleri Olgunlaştı
Pattern Matching for switch ve Record Patterns kalıcı oldu. Bu ikisi birlikte, Java'ya fonksiyonel ve veri-odaklı (data-oriented) programlamanın gücünü kazandırır.
4. Sequenced Collections
20+ yıllık bir API boşluğu (koleksiyonun ilk/son elemanına tutarlı erişim) nihayet kapandı.
5. Generational ZGC
Çok düşük gecikmeli (sub-millisecond pause) çöp toplayıcı, nesil-bazlı (generational) hale gelerek verimlilik kazandı. Büyük heap'li, gecikmeye duyarlı sistemler için ideal.
Özet: Java 17'den Java 21'e geçiş, modern bir Java ekibi için artık bir tercih değil, bir hedeftir. Virtual Threads tek başına bu geçişi haklı çıkaracak kadar değerlidir.
Genel Bakış — Java 21 Özellikleri
KALICI (Final) Özellikler
- JEP 444 — Virtual Threads — Project Loom. EN ÖNEMLİSİ.
- JEP 441 — Pattern Matching for switch — Desen eşleştirme kalıcı.
- JEP 440 — Record Patterns — İç içe yıkım (destructuring) kalıcı.
- JEP 431 — Sequenced Collections — Sıralı koleksiyon arayüzleri.
- JEP 439 — Generational ZGC — Nesil-bazlı düşük gecikmeli GC.
PREVIEW / INCUBATOR Özellikler
- JEP 430 — String Templates (1. Preview) — Güvenli string interpolasyonu.
- JEP 443 — Unnamed Patterns and Variables (Preview) —
_ile isimsiz desen/değişken. - JEP 445 — Unnamed Classes and Instance Main Methods (Preview) — Yeni başlayanlar için basit
main. - JEP 453 — Structured Concurrency (Preview).
- JEP 446 — Scoped Values (Preview).
Özellik Detayları
1. Virtual Threads (JEP 444) — KALICI — Project Loom — EN ÖNEMLİSİ
İlgili dosya:
VirtualThreadsKalici.java
NEDİR?
Virtual thread, JVM tarafından yönetilen çok hafif bir iş parçacığıdır. Geleneksel platform thread'in (OS thread'inin 1:1 sarmalayıcısı) aksine, virtual thread'ler az sayıda OS thread'i (taşıyıcı / carrier thread) üzerinde çoklanır. Milyonlarca virtual thread tek bir JVM'de var olabilir.
NEDEN GELDİ? (DERİNLEMESİNE)
Problem 1 — Platform thread'ler pahalıdır: Her platform thread bir OS thread'idir; ~1 MB stack tüketir ve OS tarafından zamanlanır. Bir sunucu pratikte birkaç bin platform thread'i aşamaz. 10.000 eşzamanlı kullanıcı = imkansız.
Problem 2 — Thread-per-request modeli ölçeklenmiyor: Java sunucularının klasik ve en okunabilir modeli "her istek için bir thread" idi. Kod basit ve senkrondur:
String veri = veritabaniSorgula(); // blokla String sonuc = baskaServisCagir(veri); // blokla yanitDon(sonuc);
Ama her bloklamada pahalı OS thread'i boşta bekler. Birkaç bin eşzamanlı istekte thread'ler tükenir; sistem yeni istek alamaz. Oysa CPU boştadır — darboğaz thread sayısıdır, işlemci değil.
Problem 3 — Reaktif programlama karmaşıktır: Sektör bu duvarı aşmak için reaktif/asenkron modellere (CompletableFuture, Reactor, RxJava) yöneldi. Bunlar az sayıda thread'le çok iş yapar AMA:
- Kod callback/operatör zincirlerine döner; okunması zordur.
- Stack trace'ler anlamsızlaşır; hata ayıklama kabusa döner.
try/catch, döngü, debugger gibi temel araçlar düzgün çalışmaz.- "Renk problemi" (function coloring): asenkron fonksiyonlar her şeyi asenkron olmaya zorlar.
Virtual Threads bu ikilemi ortadan kaldırır: Basit, senkron, bloklayıcı kod yazarsınız (okunabilirlik) ama reaktif sistemler kadar ölçeklenir (performans). İki dünyanın en iyisi.
NASIL ÇALIŞIR? (mount / unmount, carrier thread)
- Bir virtual thread çalışmak için bir carrier thread'e (platform thread) bindirilir (mount).
- Virtual thread bloklayıcı bir işleme girerse (örn.
socket.read(),Thread.sleep, JDBC çağrısı), JVM virtual thread'in durumunu (stack) heap'e kaydeder ve onu carrier'dan söker (unmount). - Boşalan carrier thread hemen başka bir virtual thread'i çalıştırmaya başlar.
- Bloklayıcı işlem tamamlandığında, virtual thread tekrar (herhangi bir) carrier'a bindirilir ve kaldığı yerden devam eder.
Sonuç: OS thread'leri asla boşta beklemez; her zaman gerçek iş yaparlar. Bloklanan iş, ucuz heap belleğinde "park" eder. Bu yüzden birkaç düzine carrier thread, milyonlarca virtual thread'e hizmet edebilir.
Pinning (sabitlenme) uyarısı:
synchronizedblok içinde bloklanan veya yerel (native) çağrı yapan virtual thread carrier'dan sökülemez ("pinned" olur). Bu, ölçeklenmeyi bozabilir. Çözüm:synchronizedyerineReentrantLockkullanın. (Java 24 ile pinning büyük ölçüde giderildi.)
GERÇEK KAZANIM
- Platform thread: ~birkaç bin eşzamanlı bağlantı tavanı.
- Virtual thread: milyonlarca eşzamanlı bağlantı, aynı donanımda.
- Kod ise eskisi gibi basit ve senkron kalır.
ESKİ vs YENİ
// ESKİ — sabit boyutlu havuz, thread sayısı darboğaz ExecutorService es = Executors.newFixedThreadPool(200); // 201. eşzamanlı uzun istek kuyruğa girer // YENİ (Java 21, KALICI) — her görev için bir virtual thread try (var es = Executors.newVirtualThreadPerTaskExecutor()) { es.submit(() -> { ... }); // milyonlarca olabilir }
GERÇEK HAYAT ÖRNEĞİ — Web Sunucu / Mikroservis
Bir mikroservis her isteği işlerken 3 ayrı servise (kullanıcı, envanter, fiyat) bloklayıcı HTTP çağrısı yapar; her çağrı ~100 ms sürer. Yani her istek ~300 ms'nin çoğunu beklemeyle geçirir.
- Platform thread (havuz 200): Aynı anda en fazla ~200 istek; daha fazlası kuyrukta bekler. Bekleme sırasında 200 pahalı OS thread'i boşta durur. Throughput düşük.
- Virtual thread: 50.000 istek aynı anda gelebilir; her biri kendi virtual thread'inde bloklanır, OS thread'leri bu sırada başka istekleri işler. Aynı donanımda çok daha yüksek throughput.
Spring Boot 3.2+, Tomcat, Helidon, Quarkus gibi framework'ler bir bayrakla virtual thread'leri etkinleştirir. Çoğu zaman kodu değiştirmeden ölçeklenirsiniz.
STRUCTURED CONCURRENCY İLE İLİŞKİSİ
Virtual thread'ler ucuz olduğundan, bir isteğin alt görevlerini (yukarıdaki 3 servis çağrısı) ayrı virtual thread'lerde paralel çalıştırmak doğaldır. Structured Concurrency (JEP 453) bu alt görevleri tek bir iş birimi gibi yönetir: birlikte başlar, biri patlarsa diğerleri otomatik iptal olur. Bu üçlü (virtual threads + structured concurrency + scoped values) modern Java sunucu mimarisinin temelidir.
AVANTAJ / DEZAVANTAJ / RİSK
- Avantaj: Basit kod + devasa ölçeklenme; reaktif karmaşıklığa veda.
- Dezavantaj/Risk: CPU-yoğun (hesaplama ağırlıklı) işler için fayda sağlamaz — onlar zaten thread'i meşgul eder.
synchronizedile pinning riski. Havuzlama (pooling) ANTI-PATTERN'dir: virtual thread'leri havuzlamayın, her görev için yenisini açın.
2. Pattern Matching for switch (JEP 441) — KALICI
İlgili dosya:
PatternMatchingSwitchKalici.java
NEDİR?
switch içinde tür desenleri (type patterns), guarded patterns (when), null işleme ve sealed hiyerarşilerle tamlık (exhaustiveness) kontrolü.
NEDEN GELDİ?
Uzun if-else instanceof zincirleri okunması zor ve hataya açıktı. Veri-odaklı kod (bir nesnenin türüne göre dallanma) için ifade gücü gerekiyordu.
ESKİ vs YENİ
// ESKİ String aciklama; if (o instanceof Integer i && i > 0) aciklama = "pozitif: " + i; else if (o instanceof String s) aciklama = "metin: " + s; else if (o == null) aciklama = "bos"; else aciklama = "diger"; // YENİ (KALICI) String aciklama = switch (o) { case null -> "bos"; case Integer i when i > 0 -> "pozitif: " + i; case Integer i -> "pozitif olmayan: " + i; case String s -> "metin: " + s; default -> "diger"; };
EVRİM
Java 17 (1.) -> 18 (2.) -> 19 (3.) -> 20 (4.) -> 21 (KALICI)
3. Record Patterns (JEP 440) — KALICI
İlgili dosya:
RecordPatternsKalici.java
NEDİR?
Record'ları eşleştirirken bileşenlerini doğrudan değişkenlere yıkma (destructuring) — özellikle iç içe (nested) yıkım.
ESKİ vs YENİ
record Adres(String sehir, String ulke) {} record Kullanici(String ad, Adres adres) {} // ESKİ if (o instanceof Kullanici k) { String sehir = k.adres().sehir(); ... } // YENİ (KALICI) — iç içe yıkım if (o instanceof Kullanici(String ad, Adres(String sehir, String ulke))) { // ad, sehir, ulke doğrudan kullanılabilir }
EVRİM
Java 19 (1.) -> 20 (2.) -> 21 (KALICI)
4. Sequenced Collections (JEP 431) — KALICI
İlgili dosya:
SequencedCollections.java
NEDİR?
Üç yeni arayüz: SequencedCollection, SequencedSet, SequencedMap. Bunlar, tanımlı bir karşılaşma sırası (encounter order) olan koleksiyonlara ilk/son elemana tutarlı erişim ve ters çevirme yetenekleri kazandırır:
getFirst(),getLast()addFirst(e),addLast(e)removeFirst(),removeLast()reversed()— ters sıralı bir görünüm (view)
NEDEN GELDİ?
20+ yıllık bir tutarsızlık vardı:
List'in ilk elemanı:list.get(0)Deque'in ilk elemanı:deque.getFirst()LinkedHashSet'in ilk elemanı: ??? —iterator().next()ile uğraşmak gerekiyordu- Son eleman almak için
List'telist.get(list.size()-1), başka koleksiyonlarda başka yollar.
Sıralı tüm koleksiyonlar için ortak ve tutarlı bir API yoktu.
ESKİ vs YENİ
// ESKİ — her tür için farklı, çirkin String ilk = list.get(0); String son = list.get(list.size() - 1); String ilkSet = linkedHashSet.iterator().next(); // son eleman çok zor! // YENİ (KALICI) — her sıralı koleksiyonda aynı String ilk = list.getFirst(); String son = list.getLast(); List<String> ters = list.reversed();
GERÇEK HAYAT ÖRNEĞİ
Bir "son görüntülenen ürünler" listesi (LinkedHashSet, eklenme sırasını korur). En son ve en eski görüntülenen ürüne erişim artık tek satır: set.getLast() / set.getFirst().
5. Generational ZGC (JEP 439) — KALICI
NEDİR?
ZGC (Z Garbage Collector), milisaniye altı duraklama (pause) süreleriyle bilinen düşük gecikmeli bir çöp toplayıcıdır. Java 21 ile nesil-bazlı (generational) hale geldi: nesneleri "genç" ve "yaşlı" nesillere ayırır.
NEDEN GELDİ?
"Çoğu nesne genç ölür" (weak generational hypothesis) gözlemine göre, genç nesilleri sık ve ucuza toplamak çok daha verimlidir. Eski (non-generational) ZGC bu avantajı kullanmıyordu.
NEREDE KOLAYLIK SAĞLAR?
Büyük heap'li (onlarca/yüzlerce GB), gecikmeye duyarlı sistemler (finansal işlem, gerçek zamanlı analitik, büyük web servisleri) için daha az CPU ve bellek ile aynı düşük gecikme.
KULLANIM
# Java 21'de Generational ZGC'yi etkinleştir java -XX:+UseZGC -XX:+ZGenerational UygulamaSinifi # (Java 23+ ile generational mod varsayılan oldu)
6. String Templates (JEP 430) — 1. PREVIEW
İlgili dosya:
StringTemplatesPreview.java
NEDİR?
Güvenli ve okunabilir string interpolasyonu. STR."Merhaba \{isim}" gibi gömülü ifadelerle string oluşturma. Sadece birleştirme değil; SQL/HTML gibi bağlamlarda kaçış (escaping) ve doğrulama yapabilen şablon işlemcileri (template processors) de sunar.
NEDEN GELDİ?
+ ile birleştirme dağınık, String.format hataya açık (argüman sırası), ve hiçbiri enjeksiyon güvenliği sağlamıyordu (SQL injection, XSS).
ESKİ vs YENİ
String isim = "Ayşe"; int yas = 30; // ESKİ String s1 = "Ad: " + isim + ", Yaş: " + yas; String s2 = String.format("Ad: %s, Yaş: %d", isim, yas); // YENİ (preview) String s3 = STR."Ad: \{isim}, Yaş: \{yas}";
NOT: String Templates Java 21 ve 22'de preview kaldı; Java 23'te kaldırıldı (geri çekildi) ve yeniden tasarlanmak üzere ertelendi. Bu yüzden üretimde kullanmayın; kavramsal olarak bilin.
EVRİM/RİSK
Java 21 (1. preview) -> 22 (2. preview) -> 23: tasarımdan KALDIRILDI. İleride farklı bir biçimde dönmesi beklenir.
7. Unnamed Patterns and Variables (JEP 443) — PREVIEW
İlgili dosya örnekleri:
RecordPatternsKalici.javaiçinde de gösterilmiştir.
NEDİR?
_ (alt çizgi) ile kullanılmayacak değişken ve desen bileşenlerini isimsiz bırakma. Niyeti açıkça belirtir: "bu değer var ama umurumda değil."
ESKİ vs YENİ
// ESKİ — kullanılmayan değişken yine de isimlendirilmeli catch (Exception e) { logla(); } // 'e' kullanılmıyor ama isim zorunlu for (var ignored : liste) sayac++; // anlamsız 'ignored' // YENİ (preview) catch (Exception _) { logla(); } for (var _ : liste) sayac++; if (o instanceof Nokta(int x, int _)) {...} // y'yi umursamıyoruz
EVRİM
Java 21 (preview) -> Java 22: KALICI (JEP 456).
8. Unnamed Classes and Instance Main Methods (JEP 445) — PREVIEW
İlgili dosya:
UnnamedMainMethod.java
NEDİR?
Yeni başlayanların "Merhaba Dünya"yı yazmak için public static void main(String[] args) ve sınıf bildirimi gibi tüm seremoniyi öğrenmesine gerek kalmadan basit main yazabilmesi.
NEDEN GELDİ?
Java'nın öğrenme eğrisindeki ilk engel, basit bir programın bile çok sayıda kavram (sınıf, public, static, void, String[]) gerektirmesiydi. Bu, eğitimde caydırıcıydı.
ESKİ vs YENİ
// ESKİ — tam seremoni public class Merhaba { public static void main(String[] args) { System.out.println("Merhaba Dünya"); } } // YENİ (preview) — sınıf gövdesi ve static gerekmez void main() { System.out.println("Merhaba Dünya"); }
EVRİM
Java 21 (preview) -> 22, 23 (gelişen preview'ler) -> Java 25: KALICI (Compact Source Files / Instance Main Methods olarak).
9. Structured Concurrency (JEP 453) — PREVIEW
İlgili dosya:
StructuredConcurrency.java
NEDİR?
Eşzamanlı alt görevleri tek bir iş birimi olarak yöneten StructuredTaskScope. Alt görevler birlikte başlar, birlikte tamamlanır/iptal olur. Hata yayılımı ve iptal otomatiktir.
NEDEN GELDİ?
Manuel ExecutorService/Future ile alt görev iptali, hata yayılımı ve sızıntı önleme zordu ("unstructured concurrency"). Virtual thread'lerle birlikte, paralel alt görevleri güvenle yönetmek için yapısal bir model gerekiyordu.
EVRİM
Java 19 (incubator) -> 20 (incubator) -> 21 (preview) -> ... olgunlaşmaya devam.
10. Scoped Values (JEP 446) — PREVIEW
NEDİR?
ThreadLocal'a değişmez, virtual thread dostu alternatif. (Detay: 13-Java-20/ScopedValuesNotlari.md.)
EVRİM
Java 20 (incubator) -> Java 21 (preview, java.lang paketine taşındı).
Geçiş Rehberi: Java 17 LTS -> Java 21 LTS
Çoğu kurum doğrudan bu sıçramayı yapar (17 -> 21). İşte özet:
| Konu | Etki | Aksiyon |
|---|---|---|
| Virtual Threads | KALICI, devrimsel | Framework bayrağıyla etkinleştir; synchronized -> ReentrantLock gözden geçir; virtual thread'leri havuzlama |
| Pattern Matching / Record Patterns | KALICI | if-else instanceof zincirlerini sadeleştir |
| Sequenced Collections | KALICI | getFirst/getLast/reversed ile kodu temizle |
| Generational ZGC | KALICI | Düşük gecikme isteyen sistemlerde -XX:+UseZGC -XX:+ZGenerational |
| String Templates | PREVIEW (sonra kaldırıldı) | Üretimde KULLANMA |
| Unnamed/Instance Main | PREVIEW | Sadece eğitim/deneme |
| Deprecation/Removal | Bazı eski API'ler kaldırıldı | jdeprscan ile tarayın |
Avantaj / Dezavantaj / Risk (Genel)
- Avantaj: Uzun destek, devrimsel eşzamanlılık, modern dil, performanslı GC. Yeni kurumsal standart.
- Risk: Preview özelliklere (String Templates) bağlanmak;
synchronizedpinning; eski kütüphanelerin Java 21 uyumu. - Tavsiye: Java 21'i yeni projeler için varsayılan hedef yapın. Mevcut Java 8/11/17 projelerini buraya taşımayı planlayın.
Bu Klasördeki Çalışan Örnekler
| Dosya | Konu | Preview? |
|---|---|---|
VirtualThreadsKalici.java | Platform vs virtual thread, binlerce eşzamanlı istek | Hayır (kalıcı) |
PatternMatchingSwitchKalici.java | switch + tür/guarded/null desenleri | Hayır (kalıcı) |
RecordPatternsKalici.java | İç içe record yıkımı + isimsiz desen | Hayır (kalıcı; _ kısmı preview) |
SequencedCollections.java | getFirst/getLast/reversed | Hayır (kalıcı) |
StringTemplatesPreview.java | STR şablon işlemcisi | Evet (preview) |
UnnamedMainMethod.java | Basit instance main | Evet (preview) |
StructuredConcurrency.java | StructuredTaskScope | Evet (preview) |
▶ Kod Örnekleri(7)
PatternMatchingSwitchKalici
çalıştırılabilir1import java.util.List;
2
3/**
4 * JAVA 21 - PATTERN MATCHING FOR SWITCH (JEP 441) - KALICI
5 * =========================================================
6 *
7 * Bu dosya, switch icinde desen eslestirmeyi (KALICI) gosterir:
8 * - tur desenleri (type patterns)
9 * - korumali desenler (guarded patterns: 'when')
10 * - null'in switch icinde ele alinmasi
11 * - sealed (muhurlu) hiyerarsi ile tamlik (exhaustiveness)
12 *
13 * EVRIM: Java 17 (1.) -> 18 (2.) -> 19 (3.) -> 20 (4.) -> 21 (KALICI)
14 *
15 * --- DERLEME / CALISTIRMA (KALICI; --enable-preview GEREKMEZ) ---
16 * javac PatternMatchingSwitchKalici.java
17 * java PatternMatchingSwitchKalici
18 */
19public class PatternMatchingSwitchKalici {
20
21 // Veri-odakli (data-oriented) modelleme icin sealed hiyerarsi
22 sealed interface Odeme permits KrediKarti, Havale, Kripto {}
23 record KrediKarti(String numara, double tutar) implements Odeme {}
24 record Havale(String iban, double tutar) implements Odeme {}
25 record Kripto(String cuzdan, double tutar, String birim) implements Odeme {}
26
27 public static void main(String[] args) {
28 System.out.println("=== JAVA 21: PATTERN MATCHING FOR SWITCH (KALICI) ===\n");
29
30 ornek1_turVeGuarded();
31 ornek2_nullIsleme();
32 ornek3_sealedTamlik();
33 }
34
35 /**
36 * Tur desenleri + korumali desenler (when).
37 * Object alip turune ve degerine gore davranir.
38 */
39 static void ornek1_turVeGuarded() {
40 System.out.println("--- Ornek 1: Tur + korumali (when) desenler ---");
41 for (Object o : List.of(42, -7, "Merhaba", 3.14, List.of(1, 2, 3))) {
42 String aciklama = switch (o) {
43 // korumali desen: tur eslesir VE kosul saglanirsa
44 case Integer i when i > 0 -> "pozitif tam sayi: " + i;
45 case Integer i -> "pozitif olmayan tam sayi: " + i;
46 case String s -> "metin (" + s.length() + " karakter): " + s;
47 case Double d -> "ondalik: " + d;
48 default -> "diger tur: " + o.getClass().getSimpleName();
49 };
50 System.out.println(" " + aciklama);
51 }
52 System.out.println();
53 }
54
55 /**
56 * null artik switch icinde ACIKCA ele alinabilir (case null).
57 * ESKIDEN switch(null) -> NullPointerException firlatirdi.
58 */
59 static void ornek2_nullIsleme() {
60 System.out.println("--- Ornek 2: null'in switch icinde ele alinmasi ---");
61 for (Object o : java.util.Arrays.asList("dolu", null, 5)) {
62 String sonuc = switch (o) {
63 case null -> "deger BOS (null)";
64 case String s -> "metin: " + s;
65 default -> "diger: " + o;
66 };
67 System.out.println(" " + sonuc);
68 }
69 System.out.println();
70 }
71
72 /**
73 * sealed arayuz + switch -> derleyici TAMLIK (exhaustiveness) garantisi verir.
74 * Tum alt turler kapsandiginda 'default' GEREKMEZ. Yeni bir alt tur eklenirse
75 * derleyici switch'i guncellemeniz icin HATA verir (guvenli evrim).
76 */
77 static void ornek3_sealedTamlik() {
78 System.out.println("--- Ornek 3: sealed hiyerarsi + tamlik (record pattern ile) ---");
79 List<Odeme> odemeler = List.of(
80 new KrediKarti("1234-5678-...", 250.0),
81 new Havale("TR12 0006 ...", 1000.0),
82 new Kripto("0xABCD...", 0.05, "BTC")
83 );
84
85 for (Odeme odeme : odemeler) {
86 // record pattern + switch: tur eslesir, alanlar yikilir, 'default' yok
87 String mesaj = switch (odeme) {
88 case KrediKarti(String numara, double tutar) ->
89 "Kredi karti odemesi: " + tutar + " TL (kart: " + numara + ")";
90 case Havale(String iban, double tutar) ->
91 "Havale: " + tutar + " TL (IBAN: " + iban + ")";
92 case Kripto(String cuzdan, double tutar, String birim) ->
93 "Kripto: " + tutar + " " + birim + " (cuzdan: " + cuzdan + ")";
94 // sealed + tum alt turler kapsandi -> default GEREKMEZ
95 };
96 System.out.println(" " + mesaj);
97 }
98 System.out.println();
99 }
100}RecordPatternsKalici
çalıştırılabilir1import java.util.List;
2
3/**
4 * JAVA 21 - RECORD PATTERNS (JEP 440) - KALICI
5 * =============================================
6 *
7 * Bu dosya, record yikimini (destructuring) KALICI haliyle, ozellikle
8 * IC ICE (nested) yikim ve isimsiz desen (_) ile gosterir.
9 *
10 * EVRIM: Java 19 (1. preview) -> 20 (2. preview) -> 21 (KALICI)
11 *
12 * NOT: Isimsiz desen / degisken (_) Java 21'de hala PREVIEW'dir (JEP 443),
13 * Java 22'de kalici oldu. Bu dosyada '_' kullanan KISIM ayri bir metotta
14 * tutulmustur ve nasil derleneceği belirtilmistir. Diger her sey KALICIDIR.
15 *
16 * --- DERLEME / CALISTIRMA ---
17 * KALICI kisimlar icin:
18 * javac RecordPatternsKalici.java
19 * java RecordPatternsKalici
20 *
21 * '_' (isimsiz desen) iceren satirlar Java 21'de PREVIEW gerektirir.
22 * Bu dosyada o ozellik YORUM icinde gosterilmistir ki dosya --enable-preview
23 * olmadan da derlensin. Denemek isterseniz yorumu acip soyle derleyin:
24 * javac --release 21 --enable-preview RecordPatternsKalici.java
25 * java --enable-preview RecordPatternsKalici
26 */
27public class RecordPatternsKalici {
28
29 // Ic ice (nested) veri modeli
30 record Adres(String sehir, String ulke) {}
31 record Kullanici(String ad, Adres adres) {}
32 record Siparis(Kullanici musteri, double tutar) {}
33
34 public static void main(String[] args) {
35 System.out.println("=== JAVA 21: RECORD PATTERNS (KALICI) ===\n");
36
37 ornek1_basitYikim();
38 ornek2_icIceYikim();
39 ornek3_switchIleYikim();
40 ornek4_isimsizDesenNotu();
41 }
42
43 /** Basit yikim: bir record'un alanlarini dogrudan degiskenlere cikar. */
44 static void ornek1_basitYikim() {
45 System.out.println("--- Ornek 1: Basit yikim ---");
46 Object o = new Adres("Istanbul", "Turkiye");
47
48 // ESKI: o instanceof Adres a -> a.sehir(), a.ulke()
49 // YENI: dogrudan yikim
50 if (o instanceof Adres(String sehir, String ulke)) {
51 System.out.println(" Sehir: " + sehir + ", Ulke: " + ulke);
52 }
53 System.out.println();
54 }
55
56 /**
57 * IC ICE YIKIM: Record patterns'in en guclu yani.
58 * Siparis -> Kullanici -> Adres zincirini TEK desende cozer.
59 */
60 static void ornek2_icIceYikim() {
61 System.out.println("--- Ornek 2: Ic ice yikim (nested destructuring) ---");
62 Object o = new Siparis(
63 new Kullanici("Ayse", new Adres("Izmir", "Turkiye")),
64 1499.90);
65
66 // Tek satirda 4 seviye derinlige inip alanlari cikariyoruz
67 if (o instanceof Siparis(Kullanici(String ad, Adres(String sehir, String ulke)),
68 double tutar)) {
69 System.out.printf(" %s adli musteri (%s/%s) %.2f TL siparis verdi.%n",
70 ad, sehir, ulke, tutar);
71 }
72 System.out.println();
73 }
74
75 /** switch + record pattern: tur ayrimi ve yikim bir arada. */
76 static void ornek3_switchIleYikim() {
77 System.out.println("--- Ornek 3: switch + record pattern ---");
78 List<Object> nesneler = List.of(
79 new Adres("Ankara", "Turkiye"),
80 new Kullanici("Mehmet", new Adres("Bursa", "Turkiye"))
81 );
82
83 for (Object o : nesneler) {
84 String mesaj = switch (o) {
85 case Adres(String s, String u) -> "Adres: " + s + " / " + u;
86 case Kullanici(String ad, Adres(String s, String u)) ->
87 "Kullanici: " + ad + " (" + s + ")";
88 default -> "bilinmeyen";
89 };
90 System.out.println(" " + mesaj);
91 }
92 System.out.println();
93 }
94
95 /**
96 * ISIMSIZ DESEN (_) - Java 21'de PREVIEW (JEP 443), Java 22'de kalici.
97 * Kullanmadigimiz bilesenleri '_' ile gosterip niyeti netlestiririz.
98 *
99 * Asagidaki kod --enable-preview ile derlenir. Bu dosya varsayilan olarak
100 * preview'siz derlensin diye ornek YORUM icinde verilmistir:
101 *
102 * if (o instanceof Siparis(Kullanici(String ad, _), double tutar)) {
103 * // adres umurumuzda degil -> '_' ile atladik
104 * System.out.println(ad + " -> " + tutar);
105 * }
106 */
107 static void ornek4_isimsizDesenNotu() {
108 System.out.println("--- Ornek 4: Isimsiz desen (_) NOTU ---");
109 System.out.println("""
110 Java 21'de '_' (isimsiz desen/degisken) PREVIEW'dir (JEP 443).
111 Kullanilmayan bilesenleri '_' ile atlamayi saglar; ornegin:
112 o instanceof Siparis(Kullanici(String ad, _), double tutar)
113 Denemek icin: javac --release 21 --enable-preview ...
114 Java 22'de bu ozellik KALICI olmustur.
115 """);
116 }
117}SequencedCollections
çalıştırılabilir1import java.util.ArrayList;
2import java.util.LinkedHashMap;
3import java.util.LinkedHashSet;
4import java.util.List;
5import java.util.SequencedCollection;
6import java.util.SequencedMap;
7import java.util.SequencedSet;
8import java.util.TreeMap;
9
10/**
11 * JAVA 21 - SEQUENCED COLLECTIONS (JEP 431) - KALICI
12 * ===================================================
13 *
14 * Bu dosya, Java 21 ile gelen UC yeni arayuzu gosterir:
15 * - SequencedCollection : getFirst/getLast/addFirst/addLast/removeFirst/removeLast/reversed
16 * - SequencedSet : SequencedCollection + Set
17 * - SequencedMap : firstEntry/lastEntry/putFirst/putLast/reversed/sequencedKeySet...
18 *
19 * NEDEN GELDI?
20 * 20+ yildir "ilk/son elemana ve ters siraya tutarli erisim" icin ortak bir
21 * API yoktu. List'te get(0)/get(size-1), Deque'te getFirst/getLast, LinkedHashSet'te
22 * ise son elemani almak cok zahmetliydi. Artik hepsinde AYNI API var.
23 *
24 * --- DERLEME / CALISTIRMA (KALICI; --enable-preview GEREKMEZ) ---
25 * javac SequencedCollections.java
26 * java SequencedCollections
27 */
28public class SequencedCollections {
29
30 public static void main(String[] args) {
31 System.out.println("=== JAVA 21: SEQUENCED COLLECTIONS (KALICI) ===\n");
32
33 listeOrnegi();
34 setOrnegi();
35 mapOrnegi();
36 eskiVsYeni();
37 }
38
39 /** List zaten SequencedCollection'dir. */
40 static void listeOrnegi() {
41 System.out.println("--- SequencedCollection (List) ---");
42 SequencedCollection<String> liste = new ArrayList<>(List.of("A", "B", "C"));
43
44 System.out.println(" Ilk eleman (getFirst): " + liste.getFirst());
45 System.out.println(" Son eleman (getLast) : " + liste.getLast());
46
47 liste.addFirst("BAS"); // basa ekle
48 liste.addLast("SON"); // sona ekle
49 System.out.println(" Ekleme sonrasi : " + liste);
50
51 System.out.println(" Ters cevrilmis (reversed): " + liste.reversed());
52
53 liste.removeFirst();
54 liste.removeLast();
55 System.out.println(" Bas/son silme sonrasi : " + liste + "\n");
56 }
57
58 /** LinkedHashSet artik SequencedSet'tir (eklenme sirasini korur). */
59 static void setOrnegi() {
60 System.out.println("--- SequencedSet (LinkedHashSet) ---");
61 SequencedSet<String> sonGoruntulenen = new LinkedHashSet<>();
62 sonGoruntulenen.add("Telefon");
63 sonGoruntulenen.add("Laptop");
64 sonGoruntulenen.add("Kulaklik");
65
66 // ESKIDEN LinkedHashSet'te son elemana erismek cok zordu!
67 System.out.println(" En ESKI goruntulenen (getFirst): " + sonGoruntulenen.getFirst());
68 System.out.println(" En YENI goruntulenen (getLast) : " + sonGoruntulenen.getLast());
69 System.out.println(" Ters sira (en yeni -> en eski) : " + sonGoruntulenen.reversed());
70 System.out.println();
71 }
72
73 /** LinkedHashMap ve TreeMap artik SequencedMap'tir. */
74 static void mapOrnegi() {
75 System.out.println("--- SequencedMap (LinkedHashMap) ---");
76 SequencedMap<String, Integer> sayfaZiyaretleri = new LinkedHashMap<>();
77 sayfaZiyaretleri.put("anasayfa", 1200);
78 sayfaZiyaretleri.put("urunler", 850);
79 sayfaZiyaretleri.put("iletisim", 300);
80
81 System.out.println(" Ilk giris (firstEntry): " + sayfaZiyaretleri.firstEntry());
82 System.out.println(" Son giris (lastEntry) : " + sayfaZiyaretleri.lastEntry());
83
84 sayfaZiyaretleri.putFirst("kampanya", 5000); // basa ekle
85 System.out.println(" putFirst sonrasi : " + sayfaZiyaretleri);
86 System.out.println(" Ters sirali map : " + sayfaZiyaretleri.reversed());
87
88 // TreeMap de SequencedMap'tir (sirali map)
89 SequencedMap<String, Integer> sirali = new TreeMap<>(sayfaZiyaretleri);
90 System.out.println(" TreeMap ilk anahtar : " + sirali.firstEntry().getKey());
91 System.out.println();
92 }
93
94 static void eskiVsYeni() {
95 System.out.println("--- ESKI vs YENI ozet ---");
96 List<String> l = List.of("ilk", "orta", "son");
97 System.out.println(" ESKI son eleman: l.get(l.size()-1) = " + l.get(l.size() - 1));
98 System.out.println(" YENI son eleman: l.getLast() = " + l.getLast());
99 System.out.println("""
100
101 * Tum sirali koleksiyonlarda artik AYNI, tutarli API.
102 * getFirst/getLast bos koleksiyonda NoSuchElementException firlatir.
103 * reversed() bir GORUNUM (view) dondurur; ozgun koleksiyona baglidir.
104 """);
105 }
106}StringTemplatesPreview
ortam gerekir1/**
2 * JAVA 21 - STRING TEMPLATES (JEP 430) - 1. PREVIEW
3 * ==================================================
4 *
5 * Bu dosya, String Templates'in Java 21'deki preview halini gosterir.
6 *
7 * !!! COK ONEMLI UYARI !!!
8 * String Templates Java 21 ve 22'de PREVIEW olarak kaldi; Java 23'te
9 * tasarimdan KALDIRILDI (geri cekildi) ve yeniden tasarlanmak uzere
10 * ertelendi. Bu yuzden URETIMDE KULLANMAYIN. Kavramsal olarak bilin.
11 * Ileride farkli bir bicimde geri donmesi beklenir.
12 *
13 * NEDIR?
14 * STR."... \{ifade} ..." sozdizimi ile guvenli, okunabilir string
15 * interpolasyonu. Ayrica SQL/HTML gibi baglamlarda kacis (escaping) ve
16 * dogrulama yapabilen sablon islemcileri (template processors) sunar.
17 *
18 * NEDEN GELDI?
19 * - "+" ile birlestirme daginiktir.
20 * - String.format argum sirasi hatalarina aciktir.
21 * - Hicbiri enjeksiyon guvenligi (SQL injection / XSS) saglamaz.
22 *
23 * --- DERLEME / CALISTIRMA (PREVIEW oldugu icin GEREKLI) ---
24 * javac --release 21 --enable-preview StringTemplatesPreview.java
25 * java --enable-preview StringTemplatesPreview
26 *
27 * NOT: Java 23+ ile bu sozdizimi KALDIRILDIGI icin o surumlerde derlenmez.
28 * Bu ornek Java 21/22 icindir.
29 */
30
31import static java.lang.StringTemplate.STR;
32
33public class StringTemplatesPreview {
34
35 public static void main(String[] args) {
36 System.out.println("=== JAVA 21: STRING TEMPLATES (1. PREVIEW) ===\n");
37
38 String isim = "Ayse";
39 int yas = 30;
40 double bakiye = 1499.90;
41
42 // --- ESKI yontemler ---
43 System.out.println("--- ESKI ---");
44 String eski1 = "Ad: " + isim + ", Yas: " + yas;
45 String eski2 = String.format("Ad: %s, Yas: %d", isim, yas);
46 System.out.println(" + ile : " + eski1);
47 System.out.println(" format ile : " + eski2);
48 System.out.println();
49
50 // --- YENI: STR sablon islemcisi (preview) ---
51 System.out.println("--- YENI (STR, preview) ---");
52 String yeni = STR."Ad: \{isim}, Yas: \{yas}";
53 System.out.println(" STR ile : " + yeni);
54
55 // Ifadeler de gomulebilir (sadece degisken degil)
56 String hesap = STR."\{isim} icin yillik bakiye: \{bakiye * 12} TL";
57 System.out.println(" Ifade ile : " + hesap);
58
59 // Cok satirli sablon
60 String rapor = STR."""
61 === MUSTERI RAPORU ===
62 Ad : \{isim}
63 Yas : \{yas}
64 Bakiye : \{bakiye} TL
65 """;
66 System.out.println(rapor);
67
68 System.out.println("""
69 --- UYARI ---
70 Bu ozellik Java 23'te KALDIRILDI. Sadece Java 21/22'de --enable-preview
71 ile calisir. Uretimde kullanmayin; ileride yeniden tasarlanacaktir.
72 """);
73 }
74}Bu sürüm-analizi örneği tek dosya olarak yerel JDK 21 ile çalıştırılamadı (bağımsız bir main içermeyebilir ya da daha yeni bir JDK / önizleme özelliği gerektirir). İlgili dil özelliği yukarıdaki anlatım ve kodda gösterilmiştir.
StructuredConcurrency
ortam gerekir1import java.time.Duration;
2import java.util.concurrent.StructuredTaskScope;
3
4/**
5 * JAVA 21 - STRUCTURED CONCURRENCY (JEP 453) - PREVIEW
6 * =====================================================
7 *
8 * Bu dosya, eszamanli alt gorevleri TEK BIR IS BIRIMI gibi yoneten
9 * StructuredTaskScope'u gosterir. Virtual Threads ile mukemmel calisir.
10 *
11 * NEDIR?
12 * Bir gorevin alt gorevleri birlikte baslar, birlikte tamamlanir veya
13 * birlikte iptal olur. Hata yayilimi ve iptal OTOMATIKTIR.
14 *
15 * NEDEN GELDI?
16 * Manuel ExecutorService + Future kullaniminda:
17 * - bir alt gorev patlarsa digerlerini iptal etmek zor,
18 * - sizinti (leak) onlemek zor,
19 * - kontrol akisi dagilir ("unstructured concurrency").
20 * StructuredTaskScope bu sorunlari yapisal olarak cozer. Her alt gorev bir
21 * VIRTUAL THREAD'de calisir (cok ucuz), bu yuzden Loom'un dogal tamamlayicisidir.
22 *
23 * --- DERLEME / CALISTIRMA (Java 21'de PREVIEW oldugu icin GEREKLI) ---
24 * javac --release 21 --enable-preview StructuredConcurrency.java
25 * java --enable-preview StructuredConcurrency
26 *
27 * NOT: StructuredTaskScope API'si surumler arasinda degisebilir (preview).
28 */
29public class StructuredConcurrency {
30
31 public static void main(String[] args) throws Exception {
32 System.out.println("=== JAVA 21: STRUCTURED CONCURRENCY (PREVIEW) ===\n");
33
34 basariliSenaryo();
35 System.out.println();
36 hataliSenaryo();
37 }
38
39 /**
40 * GERCEK HAYAT: Bir kullanici profil sayfasi icin 3 farkli servisten
41 * paralel veri cekiyoruz. ShutdownOnFailure: biri patlarsa digerleri iptal.
42 */
43 static void basariliSenaryo() throws Exception {
44 System.out.println("--- Basarili senaryo (3 servis paralel) ---");
45 long t0 = System.currentTimeMillis();
46
47 // try-with-resources: scope kapaninca tum alt gorevler temizlenir
48 try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
49 // Her fork() bir VIRTUAL thread'de calisir
50 var kullaniciF = scope.fork(() -> servisCagir("Kullanici servisi", 150, "Ayse"));
51 var siparisF = scope.fork(() -> servisCagir("Siparis servisi", 200, "42 siparis"));
52 var oneriF = scope.fork(() -> servisCagir("Oneri servisi", 100, "5 oneri"));
53
54 scope.join(); // hepsinin bitmesini bekle
55 scope.throwIfFailed(); // biri patladiysa istisna firlat
56
57 // Hepsi basarili -> sonuclari birlestir
58 System.out.println(" SONUC: " + kullaniciF.get()
59 + " | " + siparisF.get() + " | " + oneriF.get());
60 }
61
62 long sure = System.currentTimeMillis() - t0;
63 System.out.println(" Toplam sure: " + sure + " ms");
64 System.out.println(" (Seri olsa ~450 ms surerdi; paralel oldugu icin ~en yavas "
65 + "gorev kadar = ~200 ms.)");
66 }
67
68 /**
69 * Bir alt gorev hata firlatirsa: ShutdownOnFailure DIGER alt gorevleri
70 * OTOMATIK iptal eder ve hatayi yukari yayar. Sizinti olmaz.
71 */
72 static void hataliSenaryo() throws InterruptedException {
73 System.out.println("--- Hatali senaryo (bir servis patliyor) ---");
74 try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
75 scope.fork(() -> servisCagir("Hizli servis", 50, "OK"));
76 scope.fork(() -> {
77 Thread.sleep(Duration.ofMillis(80));
78 throw new RuntimeException("Odeme servisi cevap vermedi!");
79 });
80
81 scope.join();
82 scope.throwIfFailed(); // RuntimeException buradan firlar
83 System.out.println(" Buraya ulasilmaz.");
84 } catch (Exception e) {
85 // Diger alt gorevler otomatik iptal edildi
86 System.out.println(" YAKALANAN HATA: " + e.getCause().getMessage());
87 System.out.println(" (Diger alt gorevler otomatik iptal edildi; sizinti yok.)");
88 }
89 }
90
91 /** Bloklayici bir servis cagrisini taklit eder. */
92 static String servisCagir(String ad, int ms, String sonuc) throws InterruptedException {
93 Thread.sleep(Duration.ofMillis(ms));
94 System.out.println(" [" + ad + "] tamamlandi (" + ms + " ms)");
95 return sonuc;
96 }
97}Bu sürüm-analizi örneği tek dosya olarak yerel JDK 21 ile çalıştırılamadı (bağımsız bir main içermeyebilir ya da daha yeni bir JDK / önizleme özelliği gerektirir). İlgili dil özelliği yukarıdaki anlatım ve kodda gösterilmiştir.
UnnamedMainMethod
çalıştırılabilir1/**
2 * JAVA 21 - UNNAMED CLASSES & INSTANCE MAIN METHODS (JEP 445) - PREVIEW
3 * =====================================================================
4 *
5 * Bu dosya, yeni baslayanlar icin BASITLESTIRILMIS main yazimini anlatir.
6 *
7 * NEDIR?
8 * Java'da en basit programi bile yazmak icin tum seremoniyi (sinif bildirimi,
9 * public, static, void, String[] args) ogrenmek gerekiyordu. JEP 445 bunu
10 * gevsetir:
11 * - INSTANCE main: 'static' olmayan, parametresiz 'void main()' yazilabilir.
12 * - UNNAMED CLASS: bir dosyada sinif govdesi yazmadan dogrudan metot/alan
13 * tanimlanabilir; derleyici gorunmez bir sinif olusturur.
14 *
15 * NEDEN GELDI?
16 * Egitimde ilk engeli kaldirmak. Ogrenci "Merhaba Dunya" icin OOP, static,
17 * dizi gibi kavramlari bilmeden basit kod yazabilsin.
18 *
19 * !!! ONEMLI: BU DOSYA NORMAL (ISIMLI) BIR SINIFTIR !!!
20 * Gercek "unnamed class" ozelligi, sinif bildirimi OLMAYAN bir kaynak dosya
21 * gerektirir (asagida aciklandi). Bu dosya derlenebilir kalsin diye normal
22 * sinif olarak yazilmistir; preview sozdizimi YORUM icinde gosterilmistir.
23 *
24 * --- DERLEME / CALISTIRMA (bu normal dosya icin; preview gerekmez) ---
25 * javac UnnamedMainMethod.java
26 * java UnnamedMainMethod
27 *
28 * --- GERCEK UNNAMED CLASS'I DENEMEK ICIN (preview) ---
29 * Asagidaki ornegi 'Merhaba.java' adli AYRI bir dosyaya, sinif bildirimi
30 * OLMADAN yazin:
31 *
32 * void main() {
33 * System.out.println("Merhaba Dunya");
34 * }
35 *
36 * Sonra Java 21'de soyle calistirin:
37 * java --release 21 --enable-preview --source 21 Merhaba.java
38 * veya tek dosya kaynak modunda:
39 * java --enable-preview --source 21 Merhaba.java
40 *
41 * EVRIM: Java 21 (preview) -> 22, 23 (gelisen preview) -> Java 25 (KALICI,
42 * "Compact Source Files and Instance Main Methods" olarak).
43 */
44public class UnnamedMainMethod {
45
46 public static void main(String[] args) {
47 System.out.println("=== JAVA 21: UNNAMED CLASSES & INSTANCE MAIN (PREVIEW) ===\n");
48
49 System.out.println("--- ESKI (tam seremoni) ---");
50 System.out.println("""
51 public class Merhaba {
52 public static void main(String[] args) {
53 System.out.println("Merhaba Dunya");
54 }
55 }
56 """);
57
58 System.out.println("--- YENI (preview, ayri 'Merhaba.java' dosyasinda) ---");
59 System.out.println("""
60 void main() {
61 System.out.println("Merhaba Dunya");
62 }
63 """);
64
65 System.out.println("--- ARA ADIM: instance main (sinif var, static yok) ---");
66 System.out.println("""
67 public class Merhaba {
68 void main() { // 'static' ve 'String[] args' YOK
69 System.out.println("Merhaba Dunya");
70 }
71 }
72 """);
73
74 System.out.println("""
75 --- AVANTAJ / RISK ---
76 * Avantaj : Yeni baslayan dostu; ogrenme egrisini yumusatir.
77 * Risk : Java 21'de PREVIEW; sozdizimi surumler arasi degisti.
78 Kalici hali Java 25'tedir. Egitim/deneme disinda kullanmayin.
79 """);
80 }
81}VirtualThreadsKalici
çalıştırılabilir1import java.time.Duration;
2import java.time.Instant;
3import java.util.ArrayList;
4import java.util.List;
5import java.util.concurrent.ExecutorService;
6import java.util.concurrent.Executors;
7import java.util.concurrent.Future;
8import java.util.concurrent.atomic.AtomicLong;
9
10/**
11 * JAVA 21 - VIRTUAL THREADS (JEP 444) - KALICI - Project Loom
12 * ===========================================================
13 *
14 * Bu dosya, Java 21'in BAYRAK ozelligi olan Virtual Threads'i derinlemesine
15 * gosterir. Klasik (platform) thread havuzu ile virtual thread modelini,
16 * COK SAYIDA esZAMANLI BLOKLAYICI ISTEK senaryosunda kiyaslar.
17 *
18 * ==================== KAVRAMSAL OZET ====================
19 * PLATFORM THREAD:
20 * - OS thread'inin 1:1 sarmalayicisi. ~1 MB stack. OS kaynagi.
21 * - Sayisi sinirli (~binlerce). Bloklaninca pahali OS thread bosta bekler.
22 * VIRTUAL THREAD:
23 * - JVM yonetimli, cok hafif. Milyonlarca olabilir.
24 * - Az sayida "carrier" OS thread uzerinde coklanir.
25 * - Bloklayici I/O'da carrier'dan SOKULUR (unmount); carrier baska virtual
26 * thread'e gecer. Boylece OS thread asla bosta beklemez (MOUNT/UNMOUNT).
27 *
28 * NEDEN DEVRIM:
29 * "thread-per-request" modelinde basit/senkron kod yazarsiniz ama platform
30 * thread'lerle olceklenmez. Reaktif programlama olceklenir ama kod karmasik
31 * olur. Virtual threads = BASIT KOD + DEVASA OLCEKLENME.
32 *
33 * ==================== DERLEME / CALISTIRMA ====================
34 * Virtual Threads Java 21'de KALICIDIR; --enable-preview GEREKMEZ.
35 * javac VirtualThreadsKalici.java
36 * java VirtualThreadsKalici
37 *
38 * Tasiyici (carrier) thread sayisini gozlemlemek isterseniz:
39 * java -Djdk.virtualThreadScheduler.parallelism=4 VirtualThreadsKalici
40 */
41public class VirtualThreadsKalici {
42
43 /** Her "istek" ~200 ms bloklayici I/O (DB/HTTP cagrisi) taklit eder. */
44 static final Duration ISTEK_GECIKMESI = Duration.ofMillis(200);
45
46 public static void main(String[] args) throws Exception {
47 System.out.println("=== JAVA 21: VIRTUAL THREADS (KALICI) ===\n");
48 System.out.println("Mevcut islemci sayisi: "
49 + Runtime.getRuntime().availableProcessors() + "\n");
50
51 // Senaryo: 10.000 eszamanli "istek". Her biri 200 ms bloklayici bekleme.
52 // Ideal sure ~200 ms olmali (hepsi paralel beklerse).
53 int istekSayisi = 10_000;
54
55 System.out.println("--- KIYAS: " + istekSayisi
56 + " eszamanli bloklayici istek ---\n");
57
58 // 1) KLASIK: sabit boyutlu PLATFORM thread havuzu (200 thread)
59 // -> ayni anda en fazla 200 istek; geri kalanlar KUYRUKTA bekler.
60 // -> bu yuzden toplam sure cok daha uzun olur.
61 platformHavuzuIleCalistir(istekSayisi, 200);
62
63 // 2) MODERN: her gorev icin bir VIRTUAL thread
64 // -> 10.000 istek AYNI ANDA bloklanir; OS thread'leri bu sirada
65 // baska isteklere hizmet eder. Toplam sure ~tek istek suresine yakin.
66 virtualThreadIleCalistir(istekSayisi);
67
68 // 3) Virtual thread'in ic yapisini gosteren mini ornek
69 icYapiOrnegi();
70
71 // 4) Onemli uyarilar
72 uyarilar();
73 }
74
75 /**
76 * KLASIK MODEL: Sabit havuz. 200 platform thread, 10.000 gorev.
77 * Gorevler 200'erli partiler halinde isler -> ~ (10000/200) * 200ms = ~10 sn.
78 */
79 static void platformHavuzuIleCalistir(int istekSayisi, int havuzBoyutu)
80 throws InterruptedException {
81 System.out.println(">> 1) KLASIK PLATFORM THREAD HAVUZU (boyut=" + havuzBoyutu + ")");
82 AtomicLong tamamlanan = new AtomicLong();
83
84 Instant baslangic = Instant.now();
85 try (ExecutorService es = Executors.newFixedThreadPool(havuzBoyutu)) {
86 for (int i = 0; i < istekSayisi; i++) {
87 es.submit(() -> {
88 bloklayiciIstekTaklit(); // ~200 ms bekle
89 tamamlanan.incrementAndGet();
90 });
91 }
92 } // close() -> tum gorevler bitene kadar bekler
93 Duration sure = Duration.between(baslangic, Instant.now());
94
95 System.out.println(" Tamamlanan istek : " + tamamlanan.get());
96 System.out.println(" Toplam sure : " + sure.toMillis() + " ms");
97 System.out.println(" (Sadece 200 thread oldugu icin istekler partiler "
98 + "halinde islendi; sure uzadi.)\n");
99 }
100
101 /**
102 * MODERN MODEL: Her gorev icin bir virtual thread.
103 * 10.000 istek ayni anda bloklanir; toplam sure ~200 ms'ye yakin olur.
104 */
105 static void virtualThreadIleCalistir(int istekSayisi) throws InterruptedException {
106 System.out.println(">> 2) VIRTUAL THREAD (her gorev icin bir tane)");
107 AtomicLong tamamlanan = new AtomicLong();
108
109 Instant baslangic = Instant.now();
110 // newVirtualThreadPerTaskExecutor: her submit yeni bir virtual thread acar
111 try (ExecutorService es = Executors.newVirtualThreadPerTaskExecutor()) {
112 for (int i = 0; i < istekSayisi; i++) {
113 es.submit(() -> {
114 bloklayiciIstekTaklit(); // ~200 ms bekle (carrier'dan sokulur)
115 tamamlanan.incrementAndGet();
116 });
117 }
118 }
119 Duration sure = Duration.between(baslangic, Instant.now());
120
121 System.out.println(" Tamamlanan istek : " + tamamlanan.get());
122 System.out.println(" Toplam sure : " + sure.toMillis() + " ms");
123 System.out.println(" (10.000 istek AYNI ANDA bekledi; az sayida OS thread "
124 + "bu beklemeleri coklayarak yonetti.)\n");
125 }
126
127 /** Bloklayici bir ag/DB cagrisini taklit eder (CPU degil, BEKLEME aginlikli). */
128 static void bloklayiciIstekTaklit() {
129 try {
130 Thread.sleep(ISTEK_GECIKMESI);
131 } catch (InterruptedException e) {
132 Thread.currentThread().interrupt();
133 }
134 }
135
136 /** Virtual thread'in kimligini ve carrier davranisini gosteren mini ornek. */
137 static void icYapiOrnegi() throws Exception {
138 System.out.println(">> 3) VIRTUAL THREAD IC YAPISI");
139
140 List<Future<String>> sonuclar = new ArrayList<>();
141 try (var es = Executors.newVirtualThreadPerTaskExecutor()) {
142 for (int i = 1; i <= 3; i++) {
143 int no = i;
144 sonuclar.add(es.submit(() -> {
145 Thread t = Thread.currentThread();
146 // isVirtual() -> true; thread adi tipik olarak bossa "VirtualThread[#...]"
147 return " Gorev " + no + " | virtual mi? " + t.isVirtual()
148 + " | " + t;
149 }));
150 }
151 }
152 for (Future<String> f : sonuclar) System.out.println(f.get());
153 System.out.println();
154 }
155
156 static void uyarilar() {
157 System.out.println(">> 4) ONEMLI UYARILAR");
158 System.out.println("""
159 * Virtual thread'leri HAVUZLAMAYIN. Onlar ucuzdur; her gorev icin
160 YENISINI acin (newVirtualThreadPerTaskExecutor). Havuzlamak anti-pattern'dir.
161 * CPU-yogun (hesaplama agirlikli) islerde fayda saglamaz; onlar thread'i
162 zaten mesgul tutar. Virtual thread'in kazanci I/O BEKLEMESINDEDIR.
163 * 'synchronized' icinde bloklanmak PINNING'e yol acabilir (virtual thread
164 carrier'dan sokulemez). Cozum: ReentrantLock kullanin.
165 * Java 21'de KALICIDIR: --enable-preview gerekmez. Spring Boot 3.2+, Tomcat,
166 Helidon, Quarkus tek bir bayrakla virtual thread'i etkinlestirir.
167 """);
168 }
169}