Ana Sayfa/Java & Kurumsal Mimari
Java & Kurumsal Mimari·15 Ekim 2026·13 dk okuma

Project Loom Üçlemesi Tamamlanıyor: JEP 543 ile Structured Concurrency'nin Nihai Mimarisi, JEP 540 Yerleşik JSON API ve Kurumsal Mikroservislerde Eşzamanlılık Devrimi

Devoxx Belgium 2026 sahnesinde Alan Bateman ve Viktor Klang'ın paylaştığı mimari sırlar: JDK 27 (JEP 533) ile keskinleşen ve JDK 28 (JEP 543) ile kalıcı hale gelmeye hazırlanan StructuredTaskScope API'sinin derinlemesine analizi, Joiner stratejileri, yetim thread sızıntılarının sonu ve JEP 540 Simple JSON API ile Veri Odaklı Programlama (DOP) vizyonu.

Project Loom Üçlemesi Tamamlanıyor: JEP 543 ile Structured Concurrency'nin Nihai Mimarisi, JEP 540 Yerleşik JSON API ve Kurumsal Mikroservislerde Eşzamanlılık Devrimi

Dağıtık bir ödeme veya sipariş orkestrasyon servisinde en tehlikeli hatalar her şey yolunda giderken değil, alt görevlerden (subtasks) biri 200. milisaniyede beklenmedik bir SocketTimeoutException fırlattığında ortaya çıkar. Geleneksel ExecutorService, Future veya karmaşık CompletableFuture zincirleriyle yazılmış bir mikroserviste, kullanıcı doğrulama çağrısı 200. milisaniyede çökse bile, aynı metot içinde paralel başlatılan stok rezervasyonu ve kampanya hesaplama sorguları arka planda çalışmaya devam eder. Sonuçlarını kimsenin kullanmayacağı bu "yetim" (orphaned) iş parçacıkları veritabanı bağlantı havuzlarını tüketir, kuyruk gecikmelerini (tail latency) şişirir ve sessiz kaynak sızıntılarına (thread/resource leaks) yol açar.

OpenJDK dünyasında hareketli bir dönem yaşanıyor. Devoxx Belgium 2026 konferansında Java Platform Grubu mimarları Alan Bateman ve Viktor Klang'ın sunduğu "Structured Concurrency Looms" ve "Everyday JSON in Java" oturumları, Ron Pressler'ın "Java - The Year of the Runtime!" açılış konuşmasıyla birleşerek JDK 27 ve yaklaşan JDK 28'in kurumsal backend mimarilerini nasıl yeniden şekillendireceğini gözler önüne serdi.

JDK 19'da kuluçka (incubator) olarak başlayan ve Eylül 2026'da yayınlanan JDK 27'de 7. önizleme (JEP 533) aşamasına ulaşan Structured Concurrency (Yapısal Eşzamanlılık), nihayet JEP 543 ile JDK 28'de hiçbir API değişikliği olmadan kalıcı (final) hale gelmek üzere "Proposed to Target" statüsüne yükseldi. Bununla birlikte, JDK 21'de kalıcı olan Virtual Threads (JEP 444) ve JDK 25'te kalıcılaşan Scoped Values (JEP 506) sonrasında Project Loom'un büyük üçlemesi resmen tamamlanıyor.

Bu makalede, yapısal olmayan eşzamanlılığın ("eşzamanlılığın goto deyimi") neden kurumsal sistemlerde bir saatli bomba olduğunu, StructuredTaskScope ve Joiner mimarisinin JDK 25–28 arasındaki evrimini, bellek ve gecikme (latency) üzerindeki somut etkilerini ve Devoxx'ta tanıtılan diğer sürpriz gelişme olan JEP 540 (Simple JSON API) ile gözlemlenebilirlik (observability) entegrasyonunu derinlemesine inceleyeceğiz.


1. Sorunun Kökü: "Sanal Thread'ler Ucuzdur, Ancak Başlatılan İşler Değildir"

JDK 21 ile hayatımıza giren Virtual Threads (Sanal İş Parçacıkları), işletim sistemi thread'lerini (OS threads) bloklamadan milyonlarca eşzamanlı I/O işlemini yürütmemizi sağladı. Birçok mühendislik ekibi reaktif programlamanın (WebFlux / Project Reactor) bilişsel yükünden kurtulup Executors.newVirtualThreadPerTaskExecutor() kullanımına geçti. Ancak sanal thread'lerin bellek açısından "ucuz" olması, onların tetiklediği ağ çağrılarının, veritabanı kilitlerinin veya üçüncü parti API kotalarının da ucuz olduğu anlamına gelmez.

Geleneksel ExecutorService ve Future modelinde görevlerin yaşam döngüsü, kodu çağıran metodun leksikal kapsamıyla (lexical scope) sınırlandırılmamıştır:

  1. İptal Gecikmesi (Cancellation Delay): future1.get() bloklanmış beklerken future2 hata fırlatsa bile, future1 bitene kadar ana thread o hatadan haberdar olmaz.
  2. Unutulan İptaller ve Thread Sızıntısı: Bir hata yakalandığında geliştirici diğer Future nesneleri üzerinde açıkça cancel(true) çağırmayı unutursa, alt görevler metot döndükten sonra bile arka planda "hayalet" olarak çalışmaya devam eder.
  3. Gözlemlenebilirlik Körlüğü (Observability Blindness): Bir ExecutorService havuzuna veya sanal thread üreticisine gönderilen görevler, thread dump alındığında birbirinden bağımsız düz bir liste olarak görünür; hangi alt görevin hangi ana iş akışına (parent task) ait olduğu bilgisini JVM düzeyinde kaybedersiniz.

Mimari Not: "Yapısal programlama (if/for/try blokları) spagetti goto ifadelerini nasıl tek girişli ve tek çıkışlı leksikal bloklarla disipline ettiyse, Structured Concurrency de fork edilen her alt thread'in, onu başlatan kod bloğundan (scope) çıkmadan önce kesin olarak sonlanmasını (join/cancel) garanti altına alır."


2. JEP 505'ten JEP 533 ve JEP 543'e: StructuredTaskScope Mimarisi Nasıl Evrildi?

Eğer JDK 21 ile JDK 24 arasındaki erken önizleme sürümlerinde StructuredTaskScope.ShutdownOnFailure veya ShutdownOnSuccess alt sınıflarını kullandıysanız, o kodların artık geçerli olmadığını bilmelisiniz. OpenJDK ekibi, gerçek dünya geri bildirimleri doğrultusunda JDK 25 (JEP 505) ile API'yi "Kalıtım Yerine Bileşim" (Composition over Inheritance) prensibiyle baştan aşağı yeniden tasarladı.

JDK 27 (JEP 533) ve JDK 28 (JEP 543) ile son halini alan mimaride:

  • new StructuredTaskScope<>() kurucuları kaldırıldı; yerine statik StructuredTaskScope.open(...) fabrika metotları geldi.
  • Alt görevlerin nasıl birleştirileceği ve kısa devre (short-circuit) iptal politikaları StructuredTaskScope.Joiner<T, R, X> arayüzüne devredildi.
  • JEP 533'ün En Kritik Yeniliği (Tip Güvenli İstisna Modeli): JDK 26'ya kadar scope.join() metodu yalnızca bu API'ye özgü, kontrolsüz (unchecked) bir FailedException fırlatıyordu. JEP 533 ile StructuredTaskScope<T, R, X extends Throwable> ve Joiner<T, R, X extends Throwable> arayüzlerine üçüncü bir jenerik tip parametresi (X) eklendi. Artık standart joiner'lar tanıdık ExecutionException fırlatıyor veya geliştiricinin kendi belirlediği özel domain istisnasını derleme zamanı (compile-time) tip güvenliğiyle doğrudan yükseltebiliyor.

Geleneksel Yaklaşım vs. JEP 533 / JEP 543 Yaklaşımı

Mimariler arasındaki farkı somutlaştırmak için metrikleri karşılaştıralım:

Kriter ExecutorService + Future CompletableFuture.allOf/anyOf StructuredTaskScope (JEP 533 / 543)
Yaşam Döngüsü Sınırı Belirsiz (Metot bitse de thread yaşayabilir) Zincir bazlı (Takibi ve hata ayıklaması zor) Kesin Leksikal Kapsam (try-with-resources)
Erken İptal (Short-Circuit) Manuel kodlama gerektirir, ilk get() bloklar Karmaşık exceptionally / cancel sarmalları Otomatik (Hata anında kardeş thread'lere interrupt)
Kapsam İçi Zaman Aşımı Her Future.get(timeout) için ayrı hesaplama orTimeout() (İptal yayılımı garanti değil) cf.withTimeout(Duration) ile tüm kapsama tek sınır
Thread Dump Görünürlüğü Düz (Flat) liste, ebeveyn-çocuk ilişkisi yok Callback yığınları (Stack trace kopukluğu) JSON Thread Dump'ta tam ağaç hiyerarşisi
Context Yayılımı ThreadLocal (Kopyalama maliyeti ve sızıntı riski) Manuel Context taşıma ScopedValue ile sıfır kopyalama maliyetli miras

3. Gerçek Dünya Senaryosu: Spring Boot Mikroservisinde Sipariş Orkestrasyonu

Bir e-ticaret ödeme sayfasında (Checkout), kullanıcının profilini, sepet kalemlerini, kargo tahminini ve kişiselleştirilmiş kuponlarını paralel olarak çeken bir Spring Boot servisi düşünelim. Kullanıcı, sepet ve kargo servisleri zorunludur (biri bile çökerse işlem 200ms içinde anında iptal edilmelidir); ayrıca işlem toplamda 800 milisaniyeyi geçmemelidir.

JDK 27 (--enable-preview) ve JDK 28 (standart) ile bu mimariyi ScopedValue ve StructuredTaskScope kullanarak kodlayalım:

java
package com.tastutanlabs.checkout.orchestration;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.util.concurrent.StructuredTaskScope.Subtask;
import java.util.concurrent.StructuredTaskScope.TimeoutException;
import org.springframework.stereotype.Service;

@Service
public class CheckoutOrchestrationService {

    // JDK 25+ ile kalıcılaşan ScopedValue: Tüm alt sanal thread'lere otomatik ve güvenli miras!
    public static final ScopedValue<String> TRACE_ID = ScopedValue.newInstance();
    public static final ScopedValue<String> TENANT_ID = ScopedValue.newInstance();

    private final CustomerClient customerClient;
    private final CartClient cartClient;
    private final ShippingClient shippingClient;

    public CheckoutOrchestrationService(
            CustomerClient customerClient,
            CartClient cartClient,
            ShippingClient shippingClient) {
        this.customerClient = customerClient;
        this.cartClient = cartClient;
        this.shippingClient = shippingClient;
    }

    public CheckoutAggregatedResponse prepareCheckout(
            long customerId, String cartId, String traceId, String tenantId) {

        // Bağlamı (Context) ScopedValue ile bağlıyoruz; alt görevler otomatik olarak erişecek
        return ScopedValue.where(TRACE_ID, traceId)
                .where(TENANT_ID, tenantId)
                .call(() -> executeStructuredCheckout(customerId, cartId));
    }

    private CheckoutAggregatedResponse executeStructuredCheckout(long customerId, String cartId) {
        // JEP 533 / JEP 543: Varsayılan Joiner (allUntil/allSuccessfulOrThrow mantığı) ve Yapılandırma
        try (var scope = StructuredTaskScope.open(
                Joiner.awaitAllSuccessfulOrThrow(),
                cf -> cf.withName("checkout-orchestrator")
                        .withTimeout(Duration.ofMillis(800)))) {

            // Her fork() çağrısı yeni bir Virtual Thread başlatır ve ScopedValue bağlamını miras alır
            Subtask<CustomerProfile> customerTask = scope.fork(() -> 
                customerClient.fetchProfile(customerId, TRACE_ID.get())
            );

            Subtask<CartDetails> cartTask = scope.fork(() -> 
                cartClient.fetchCart(cartId, TRACE_ID.get())
            );

            Subtask<ShippingQuote> shippingTask = scope.fork(() -> 
                shippingClient.estimateShipping(cartId, TENANT_ID.get())
            );

            // Tek senkronizasyon noktası: Biri hata verirse diğerleri ANINDA interrupt edilir!
            scope.join();

            // join() başarılı döndüyse tüm alt görevlerin SUCCESS durumunda olduğu garanti edilir
            return new CheckoutAggregatedResponse(
                    customerTask.get(),
                    cartTask.get(),
                    shippingTask.get()
            );

        } catch (ExecutionException ex) {
            // JEP 533 ile geri dönen tanıdık ExecutionException ve Pattern Matching ile hata yönetimi
            throw switch (ex.getCause()) {
                case CustomerSuspendedException cse -> new DomainCheckoutException("Müşteri hesabı askıda", cse);
                case OutOfStockException oose -> new DomainCheckoutException("Sepetteki ürün tükendi", oose);
                case Throwable t -> new DomainCheckoutException("Alt servis hatası: " + t.getMessage(), t);
            };
        } catch (TimeoutException ex) {
            // 800ms aşılırsa çalışan tüm alt thread'ler otomatik iptal edilir ve scope temiz kapanır
            throw new GatewayTimeoutException("Checkout orkestrasyonu 800ms SLA süresini aştı", ex);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new DomainCheckoutException("İşlem kesintiye uğradı", ex);
        }
    }
}

Bu Kodda Arka Planda (JVM Düzeyinde) Ne Oluyor?

  1. Sıfır Gecikmeli Kısa Devre (Zero-Latency Short-Circuiting): cartClient.fetchCart 120. milisaniyede OutOfStockException fırlattığı anda, Joiner durumu yakalar, kapsamı iptal durumuna geçirir ve hâlâ ağ yanıtı bekleyen customerTask ile shippingTask sanal thread'lerine anında Thread.interrupt() sinyali gönderir. try-with-resources bloğu kapanmadan önce her iki iptal edilen thread'in de sonlandığı garanti edilir; ancak ana metot 800ms beklemek yerine 120. milisaniyede yanıt döner.
  2. Üçüncü Tip Parametresiyle Özel İstisna Sarmalama: Eğer ExecutionException yakalamak istemiyorsanız, JEP 533'ün sunduğu yeni fabrika metoduyla doğrudan kendi çalışma zamanı (runtime) istisnanızı fırlatabilirsiniz:
    java
    try (var scope = StructuredTaskScope.open(
            Joiner.<PriceQuote, DomainPricingException>allSuccessfulOrThrow(DomainPricingException::new))) {
        // ... fork işlemleri
        List<PriceQuote> quotes = scope.join(); // Doğrudan List<PriceQuote> döner ve DomainPricingException fırlatır!
    }

4. İleri Seviye Mimari Desen: Özel Joiner ile "Hedging / Quorum" ve Kısmi Başarı Yönetimi

Alan Bateman ve Viktor Klang'ın Devoxx Belgium 2026 konuşmasında özellikle vurguladığı nokta, Joiner arayüzünün ne kadar esnek bir yapı taşı olduğudur. Yerleşik olarak gelen fabrika metotları şunlardır:

  • Joiner.awaitAllSuccessfulOrThrow(): Farklı tipteki alt görevlerin tamamı başarılı olana kadar bekler (join() null döner, sonuçlar Subtask::get ile alınır).
  • Joiner.allSuccessfulOrThrow(): Aynı tipteki alt görevlerin tamamı başarılı olduğunda sonuçları doğrudan List<T> olarak döner.
  • Joiner.anySuccessfulOrThrow(): İlk başarılı olan alt görevin sonucunu (T) döner ve diğer tüm yavaş alternatifleri anında iptal eder (Multi-region cache okuma veya yedekli LLM/ödeme sağlayıcı sorgulama için mükemmeldir).
  • Joiner.allUntil(Predicate<Subtask<? extends T>>): Belirli bir koşul sağlanana kadar çalışmaya devam eder.

Peki ya kurumsal bir öneri (recommendation) veya fiyat toplama motorunda en az 2 servisin başarılı olması yeterli ise ve zaman aşımı (timeout) gerçekleştiğinde bile o ana kadar toplanan sonuçlarla yola devam etmek (Graceful Degradation) istiyorsak? JEP 525 ve JEP 533 ile Joiner arayüzüne eklenen onTimeout() kancası (hook) burada devreye girer:

java
package com.tastutanlabs.checkout.resilience;

import java.time.Duration;
import java.util.Queue;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.util.concurrent.StructuredTaskScope.Subtask;

/**
 * En az 'minRequired' kadar başarılı yanıt toplandığında veya timeout olduğunda
 * eldeki kısmi sonuçları (Graceful Degradation) döndüren özel Joiner.
 */
public class QuorumWithFallbackJoiner<T> implements Joiner<T, List<T>, QuorumUnavailableException> {

    private final int maxTarget;
    private final int minRequired;
    private final Queue<T> results = new ConcurrentLinkedQueue<>();

    public QuorumWithFallbackJoiner(int minRequired, int maxTarget) {
        this.minRequired = minRequired;
        this.maxTarget = maxTarget;
    }

    @Override
    public boolean onComplete(Subtask<? extends T> subtask) {
        if (subtask.state() == Subtask.State.SUCCESS) {
            results.add(subtask.get());
            // Hedeflenen maksimum yanıta ulaştıysak true dönerek kalan yavaş görevleri iptal et!
            return results.size() >= maxTarget;
        }
        // Hataları yutuyoruz (loglanabilir), diğer görevlerin tamamlanmasına izin veriyoruz
        return false;
    }

    @Override
    public void onTimeout() {
        // JEP 525 / JEP 533: TimeoutException fırlatmak yerine, eğer minRequired sağlanmışsa
        // hiçbir şey yapmayarak result() metodunun çağrılmasına izin veriyoruz!
        if (results.size() < minRequired) {
            throw new QuorumUnavailableException(
                "Zaman aşımı! Beklenen minimum yanıt: " + minRequired + ", alınan: " + results.size()
            );
        }
    }

    @Override
    public List<T> result() throws QuorumUnavailableException {
        if (results.size() < minRequired) {
            throw new QuorumUnavailableException(
                "Yeterli çoğunluk sağlanamadı. Alınan yanıt sayısı: " + results.size()
            );
        }
        return List.copyOf(results);
    }
}

Bu özel Joiner, örneğin 5 farklı tedarikçi API'sine paralel fiyat sorgusu gönderip, ilk yanıt veren 3 tedarikçinin fiyatını alır almaz kalan 2 yavaş tedarikçi bağlantısını keser; eğer 300ms içinde sadece 2 tedarikçi yanıt vermişse onTimeout() devreye girer ve sistemi çökertmek yerine eldeki 2 fiyatla sayfayı render eder. Aynı mantığı geleneksel CompletableFuture ve CountDownLatch ile hatasız ve thread-safe yazmak onlarca satırlık kırılgan senkronizasyon kodu gerektirirdi.

Mimari Uyarı: Joiner nesneleri durum (state) tutabilir ve kesinlikle tek kullanımlıktır. Bir Joiner örneğini birden fazla StructuredTaskScope arasında paylaşmak veya kapsam kapandıktan sonra yeniden kullanmak ciddi yarış koşullarına (race conditions) yol açar. Her StructuredTaskScope.open(...) çağrısında yeni bir Joiner üretilmelidir.


5. Devoxx Belgium 2026'nın Diğer Büyük Sürprizi: JEP 540 (Simple JSON API) ve Gözlemlenebilirlik

Alan Bateman ve Viktor Klang'ın bu hafta yayınlanan ikinci konuşması "Everyday JSON in Java", JDK 28'e hedeflenen JEP 540: Simple JSON API (jdk.incubator.json) üzerineydi. İlk bakışta "Neden Jackson veya Gson varken JDK içine bir JSON API ekleniyor?" sorusu akla gelebilir. Ancak mimari gerekçe son derece nettir:

  1. Sıfır Bağımlılık ve Veri Odaklı Programlama (DOP): Küçük bir yapılandırma dosyası okumak, bir AI ajanından (MCP / LLM endpoint) dönen basit bir JSON yanıtını ayrıştırmak veya CLI aracı yazmak için projeye koca bir veri bağlama (data-binding) kütüphanesi eklemek gereksiz bir yük oluşturur. JEP 540, Java'nın modern sealed arayüzlerini ve switch pattern matching yeteneklerini kullanan, RFC 8259 standardına %100 katı (strict) uyumlu, değiştirilemez (immutable) bir değer ağacı sunar (JsonValue -> JsonObject, JsonArray, JsonString, JsonNumber, JsonBoolean, JsonNull).
  2. JDK'nın Kendi Ürettiği JSON Çıktılarını Tüketmek: İşte Project Loom ile kesişen en güzel nokta! StructuredTaskScope kullandığınızda, JVM ebeveyn-çocuk thread hiyerarşisini bilir ve jcmd <pid> Thread.dump_to_file -format=json dump.json komutuyla JSON formatında yapısal bir thread dökümü üretir.

JDK 28'de harici hiçbir kütüphane olmadan, JEP 540 ile bir JVM JSON thread dökümünü okuyup hangi StructuredTaskScope altında kaç sanal thread'in çalıştığını birkaç satırda analiz edebiliriz:

java
// JDK 28: --add-modules jdk.incubator.json
import jdk.incubator.json.*;
import java.nio.file.Files;
import java.nio.file.Path;

public class LoomThreadDumpInspector {

    public static void inspectStructuredScopes(Path jsonDumpPath) throws Exception {
        String rawJson = Files.readString(jsonDumpPath);

        // JEP 540: Katı RFC 8259 ayrıştırıcı ve akıcı (fluent) gezinme
        JsonValue root = Json.parse(rawJson);
        JsonArray containers = root.get("threadDump")
                                   .get("threadContainers")
                                   .asArray();

        for (JsonValue container : containers.values()) {
            // Sealed JsonValue hiyerarşisi ile Pattern Matching
            if (container instanceof JsonObject obj) {
                String containerName = obj.get("container").asString();
                String parentName = obj.tryGet("parent")
                                       .map(JsonValue::asString)
                                       .orElse("ROOT");
                int threadCount = obj.get("threads").asArray().values().size();

                if (containerName.contains("checkout-orchestrator")) {
                    System.out.printf("Scope: %s | Ebeveyn: %s | Aktif Sanal Thread: %d%n",
                            containerName, parentName, threadCount);
                }
            }
        }
    }
}

6. Bellek, Gecikme (Tail Latency) ve Throughput Analizi

Kurumsal üretim ortamlarında (production) StructuredTaskScope mimarisine geçişin sistem metriklerine etkisi üç ana eksende ölçülür:

  • P99 / P99.9 Kuyruk Gecikmesi (Tail Latency) İyileşmesi: Dağıtık mimarilerde en yavaş alt servis, tüm yanıt süresini belirler. Joiner.anySuccessfulOrThrow() ile yapılan yedekli (hedged) çağrılar veya hata anında anında devreye giren yapısal iptal mekanizması, başarısız isteklerin sistemde kalma süresini (Mean Time to Failure Response) saniyelerden milisaniyelere indirir.
  • Bağlantı Havuzu ve Bellek Korunumu: Bir alt görev çöktüğünde kardeş görevlerin derhal interrupt edilmesi, devam eden gereksiz JDBC sorgularının ve HTTP soket okumalarının iptal edilmesini sağlar. Bu durum özellikle ani trafik patlamalarında (traffic spikes) HikariCP bağlantı havuzunun veya aşağı akış (downstream) mikroservislerin tükenmesini (cascading failure) engeller.
  • Project Lilliput (Compact Object Headers) ile Sinerji: Ron Pressler'ın "Java - The Year of the Runtime!" konuşmasında da değindiği üzere, JDK 27 ve 28'de olgunlaşan Compact Object Headers (nesne başlıklarının 128 bitten 64 bite indirilmesi), milyonlarca kısa ömürlü Subtask, ScopedValue ve JsonValue nesnesinin oluşturulduğu yüksek throughput'lu servislerde heap bellek tüketimini %10 ila %20 oranında düşürerek CPU önbellek (L1/L2 cache) isabet oranını artırır.

7. Kurumsal Backend Ekipleri İçin Pratik Geçiş Tavsiyeleri

  1. JDK 21–24 Önizleme Kodlarını Temizleyin: Kod tabanınızda eski ShutdownOnFailure veya ShutdownOnSuccess sınıflarını kullanan denemeler varsa, bunları JDK 27 (JEP 533) ve JDK 28 (JEP 543) ile kalıcılaşan StructuredTaskScope.open(Joiner) yapısına yükseltin. JEP 543, API'yi JDK 27'deki haliyle birebir kalıcılaştıracağı için bugünden JDK 27 yapısı üzerine kurulan mimariler JDK 28'de sadece --enable-preview bayrağı kaldırılarak çalışacaktır.
  2. Kesinti (Interruption) Dostu I/O Kütüphaneleri Kullanın: Yapısal eşzamanlılığın iptal mekanizması Thread.interrupt() üzerine kuruludur. Alt görevlerinizin içinde InterruptedException'ı yutan (catch (InterruptedException e) {}) eski kodlar veya kesintiye yanıt vermeyen bloklayıcı çağrılar varsa, scope.close() bu görevlerin bitmesini beklerken gecikecektir. Modern HttpClient, güncel JDBC sürücüleri ve Spring Boot 3.4+/4.x bileşenlerinin kesinti sinyallerine doğru tepki verdiğinden emin olun.
  3. ThreadLocal Yerine ScopedValue Dönüşümünü Başlatın: StructuredTaskScope içindeki alt görevler yalnızca ScopedValue bağlamlarını güvenli ve sıfır kopyalama maliyetiyle miras alır. Güvenlik bağlamı (SecurityContext), korelasyon kimliği (Trace ID) ve çoklu kiracı (Multi-tenancy) bilgilerini ThreadLocal'dan ScopedValue'ya taşımak, sanal thread'lerin bellek ayak izini minimumda tutmanın anahtarıdır.
  4. JSON İşlemlerinde Katmanlı Strateji Belirleyin: Büyük domain nesnelerinin serileştirilmesi ve Spring MVC/WebFlux uç noktaları için Jackson vazgeçilmez olmaya devam edecektir. Ancak iç araçlar, sağlık kontrolleri (health checks), JFR/Thread Dump analizörleri ve hafif ajan entegrasyonları için JDK 28 ile gelecek JEP 540 (jdk.incubator.json) modülünü radarınıza alın.

Sonuç

Yapay zeka kodlama ajanlarının sözdizimini (syntax) üretmeyi ucuzlattığı bir çağda, Ron Pressler'ın da vurguladığı gibi asıl mühendislik değeri çalışma zamanı (runtime) güvenilirliği, gözlemlenebilirlik ve operasyonel mükemmellikte yatıyor. JEP 543 (Structured Concurrency), sanal thread'lerin getirdiği ham performansı kurumsal düzeyde öngörülebilir, sızıntısız ve izlenebilir bir mühendislik disiplinine kavuşturuyor. Eşzamanlılıkta "spagetti" dönemi kapanıyor; yapısal, güvenli ve gözlemlenebilir çalışma zamanı çağı başlıyor.

Konu Etiketleri
#Kurumsal Mimari#Java#OpenJDK#Project Loom#Structured Concurrency#JEP 543#JEP 540#Spring Boot
Emre Taştutan
Emre TaştutanGeliştirici & AI Meraklısı

Yazılım mimarisi, mikroservis ekosistemleri ve üretken yapay zeka uygulamaları üzerine çalışıyorum. TastutanLabs çatısı altında geliştirici araçları ve SaaS ürünleri inşa ediyorum.

Bu Yazıyı Paylaş:

Yorumlar (0)

Düşüncelerinizi Paylaşın

Henüz yorum yapılmamış. İlk yorumu siz yapın!