Spring Boot 3.4 Virtual Threads: Mülakat Soruları ve Performans Karşılaştırmaları

Java 21 Virtual Threads'i Spring Boot 3.4 ile öğrenin: 15 mülakat sorusu, performans karşılaştırmaları ve teknik mülakatlarda fark yaratacak göç desenleri.

Spring Boot 3.4 Virtual Threads: mülakat soruları ve performans karşılaştırmaları

Virtual Threads, Java 21'in en önemli yeniliklerinden biridir ve Spring Boot 3.4 onları yerel olarak destekler. Project Loom'un bu özelliği, backend uygulamalarında eşzamanlılık yönetimini köklü biçimde değiştirir. Teknik mülakatlar artık iç mekanizmaların, uygun kullanım senaryolarının ve sık rastlanan tuzakların kavranmasını ölçer.

Hazırlık İpucu

Mülakatçılar Virtual Threads'i gerçekten anlayan adayları, onları körlemesine kullananlardan ayırır. Ne zaman KULLANILMAMASI gerektiğini bilmek, faydalarını bilmek kadar önemlidir.

Virtual Threads Temelleri

Soru 1: Virtual Thread nedir ve Platform Thread'den nasıl farklıdır?

Virtual Thread, işletim sistemi yerine JVM tarafından yönetilen hafif bir thread'dir. Platform Threads'in (klasik thread'ler) aksine Virtual Threads doğrudan OS thread'lerine eşlenmez. JVM, bunlardan milyonlarcasını çok düşük bellek kullanımıyla oluşturabilir.

VirtualThreadDemo.javajava
// Comparing thread creation approaches
public class VirtualThreadDemo {

    public void demonstrateDifference() {
        // Platform Thread: ~1MB stack per thread
        // Practical limit: a few thousand on a standard JVM
        Thread platformThread = new Thread(() -> {
            performBlockingOperation();
        });

        // Virtual Thread: ~a few KB per thread
        // Can create millions without issues
        Thread virtualThread = Thread.ofVirtual().start(() -> {
            performBlockingOperation();
        });
    }

    // A Virtual Thread "mounts" onto a Platform Thread (carrier)
    // During I/O blocking, it releases the carrier for other Virtual Threads
    private void performBlockingOperation() {
        try {
            Thread.sleep(1000); // Virtual Thread detaches from carrier here
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Temel fark, bloklanma sırasındaki davranıştadır. Platform Thread bloklandığında (I/O, sleep) OS thread'ine bağlı kalır. Virtual Thread ise taşıyıcı thread'den "unmount" olur ve taşıyıcının başka Virtual Threads tarafından kullanılmasına izin verir.

Soru 2: Spring Boot 3.4'te Virtual Threads nasıl etkinleştirilir?

Spring Boot 3.4, Virtual Threads etkinleştirmesini tek bir konfigürasyon özelliğine indirgemiştir. Tüm framework otomatik olarak adapte olur: Tomcat, REST controller'ları ve bloklayıcı çağrılar bu optimizasyondan anında yararlanır.

yaml
# application.yml
# Global Virtual Threads activation
spring:
  threads:
    virtual:
      enabled: true

# Optional Tomcat pool configuration
server:
  tomcat:
    threads:
      max: 200  # Less critical with Virtual Threads
      min-spare: 10
WebConfig.javajava
// Programmatic activation if needed
@Configuration
public class WebConfig {

    @Bean
    public TomcatProtocolHandlerCustomizer<?> virtualThreadCustomizer() {
        // Each HTTP request runs on a Virtual Thread
        return protocolHandler -> {
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
}

Etkinleştirme Tomcat'in davranışını değiştirir: sabit bir thread havuzu yerine her istek kendi Virtual Thread'ini alır. Bu yaklaşım, klasik thread havuzu darboğazını ortadan kaldırır.

Soru 3: "Mounting" ve "unmounting" kavramlarını açıklayın

Mounting, bir Virtual Thread'in taşıyıcı thread'e (Platform Thread) bağlanmasını ifade eder. Unmounting ise bloklayıcı işlemler sırasında gerçekleşir ve taşıyıcıyı diğer Virtual Threads için serbest bırakır. Bu mekanizma CPU kaynaklarının optimum kullanımını sağlar.

MountingDemo.javajava
// Illustrating the mounting/unmounting cycle
public class MountingDemo {

    public void demonstrateMounting() {
        Thread.ofVirtual().start(() -> {
            // MOUNTED: Virtual Thread is using a carrier thread
            System.out.println("Carrier: " + getCurrentCarrier());

            // UNMOUNTING: releases carrier during blocking
            performDatabaseQuery(); // Blocking JDBC call

            // REMOUNTED: may be on a different carrier
            System.out.println("New carrier: " + getCurrentCarrier());
        });
    }

    // Blocking operations trigger unmounting automatically
    private void performDatabaseQuery() {
        // JDBC connection, file read, network call...
        // Virtual Thread detaches during I/O wait
    }

    private String getCurrentCarrier() {
        // Gets the current carrier thread name
        return Thread.currentThread().toString();
    }
}

Bu mekanizma geliştirici için saydamdır. Kod klasik imperatif tarzda yazılır, ancak JVM taşıyıcı kullanımını otomatik olarak optimize eder. Birkaç taşıyıcıdan oluşan bir havuz milyonlarca Virtual Thread'e hizmet verebilir.

Teknik Not

Taşıyıcı thread sayısı varsayılan olarak CPU çekirdek sayısına eşittir. JVM bu havuzu ForkJoinPool aracılığıyla dinamik biçimde ayarlar.

Kullanım Senaryoları ve Anti-Patternler

Soru 4: Virtual Threads ne zaman performans kazancı sağlar?

Virtual Threads, I/O ağırlıklı yüklerde parlar: harici REST çağrıları, veritabanı sorguları, dosya okumaları. Bu işlemler zamanın büyük kısmını beklemekle geçirir; bu sırada Virtual Thread taşıyıcısını serbest bırakır.

IOBoundService.javajava
// Ideal case for Virtual Threads
@Service
public class IOBoundService {

    private final RestClient restClient;
    private final UserRepository userRepository;

    // Each call involves network and database waiting
    // Virtual Threads shine here
    public UserProfile enrichUserProfile(Long userId) {
        // DB call - VT detaches during SQL query
        User user = userRepository.findById(userId).orElseThrow();

        // External REST call - VT detaches during HTTP wait
        ExternalData externalData = restClient
            .get()
            .uri("/api/external/{id}", userId)
            .retrieve()
            .body(ExternalData.class);

        // Data aggregation
        return new UserProfile(user, externalData);
    }
}

Kazanç çok daha fazla eşzamanlı isteğin işlenmesinden gelir. 200 Platform Thread ve 100ms süren isteklerle maksimum throughput 2.000 req/s'dir. Virtual Threads ile aynı makinede 50.000+ req/s mümkündür.

Soru 5: Virtual Threads ile hangi anti-patternlerden kaçınmak gerekir?

Virtual Threads, CPU ağırlıklı yükler ve "pinning"e neden olan durumlar için uygun değildir. Pinning, bir Virtual Thread'in bloklanmaya rağmen taşıyıcısına bağlı kalmasıyla ortaya çıkar ve sanallaştırmanın faydalarını ortadan kaldırır.

AntiPatterns.javajava
// Examples of cases to avoid
@Service
public class AntiPatterns {

    // ANTI-PATTERN 1: CPU-intensive computation
    // Virtual Threads provide no benefit here
    public BigInteger computeFactorial(int n) {
        // 100% CPU, no I/O, no unmounting possible
        BigInteger result = BigInteger.ONE;
        for (int i = 2; i <= n; i++) {
            result = result.multiply(BigInteger.valueOf(i));
        }
        return result; // Carrier is monopolized throughout
    }

    // ANTI-PATTERN 2: Synchronized causes pinning
    private final Object lock = new Object();

    public void pinnedOperation() {
        synchronized (lock) { // PINNING: VT stays on carrier
            performDatabaseQuery(); // Unmounting doesn't happen!
        }
    }

    // SOLUTION: Use ReentrantLock
    private final ReentrantLock reentrantLock = new ReentrantLock();

    public void unpinnedOperation() {
        reentrantLock.lock();
        try {
            performDatabaseQuery(); // Unmounting possible
        } finally {
            reentrantLock.unlock();
        }
    }
}

Pinning, kaynak açısından Virtual Thread'i Platform Thread'e dönüştürür. Başlıca nedenler synchronized blokları ve yerel JNI çağrılarıdır. ReentrantLock'a geçiş ilk durumu çözer.

Soru 6: Bir uygulamada pinning nasıl tespit edilir?

JVM, pinning vakalarını tespit etmek için tanılama seçenekleri sunar. Bu bilgi, Virtual Threads'e geçişte kritik öneme sahiptir; çünkü pinning performansı iyileştirmek yerine bozabilir.

PinningDiagnostics.javajava
// Configuration and pinning detection
public class PinningDiagnostics {

    // JVM option to log pinning
    // -Djdk.tracePinnedThreads=full (detailed)
    // -Djdk.tracePinnedThreads=short (summary)

    // Example code causing pinning
    public void demonstratePinning() {
        Thread.ofVirtual().start(() -> {
            synchronized (this) {
                // This log will appear with tracePinnedThreads enabled
                try {
                    Thread.sleep(100); // Pinned during sleep!
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }
}
bash
# Typical output with -Djdk.tracePinnedThreads=full
Thread[#23,VirtualThread[#1]/runnable@ForkJoinPool-1-worker-1,5,CarrierThreads]
    java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183)
    java.base/java.lang.VirtualThread.parkOnCarrierThread(VirtualThread.java:661)
    com.example.PinningDiagnostics.demonstratePinning(PinningDiagnostics.java:15)

Pinning loglarının analizi düzeltilmesi gereken sıcak noktaları ortaya çıkarır. Sık pinning yaşayan bir uygulama Virtual Threads'i tam kullanamaz ve Platform Threads'ten bile yavaş olabilir.

Spring Boot mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Performans Karşılaştırmaları

Soru 7: Virtual Threads'ten ne kadar performans kazancı beklenebilir?

Karşılaştırmalar, tipik I/O ağırlıklı uygulamalarda kayda değer iyileşmeler gösterir. Kazançlar I/O süresi / CPU süresi oranına ve gerekli eşzamanlılık seviyesine bağlıdır.

BenchmarkController.javajava
// Endpoint for measuring performance
@RestController
@RequestMapping("/api/benchmark")
public class BenchmarkController {

    private final ExternalApiClient apiClient;

    // Simulation of a typical endpoint with external calls
    @GetMapping("/user/{id}")
    public ResponseEntity<UserData> getUser(@PathVariable Long id) {
        // Three sequential I/O calls
        UserInfo info = apiClient.fetchUserInfo(id);        // ~50ms
        List<Order> orders = apiClient.fetchOrders(id);     // ~80ms
        CreditScore score = apiClient.fetchCreditScore(id); // ~100ms

        return ResponseEntity.ok(new UserData(info, orders, score));
    }
}
text
# Benchmark results - 10,000 concurrent requests
# Configuration: 8 cores, 16GB RAM, simulated latency 230ms/request

Platform Threads (pool 200):
- Throughput: 850 req/s
- P99 latency: 1250ms
- Heap memory: 2.1GB

Virtual Threads:
- Throughput: 4200 req/s
- P99 latency: 280ms
- Heap memory: 850MB

Gain: 5x throughput, 4.5x P99 latency reduction

Virtual Threads ayrıca bellek kullanımını da düşürür; her thread Platform Thread'in yaklaşık 1MB'sı yerine yalnızca birkaç KB ayırır.

Soru 8: Virtual Threads ile bağlantı havuzları nasıl yapılandırılır?

Bağlantı havuzları (HikariCP, Lettuce) Virtual Threads ile birlikte yeni darboğaz haline gelir. 10 bağlantılı bir havuz, milyonlarca Virtual Thread olsa bile aynı anda 10 DB sorgusuyla sınırlıdır.

yaml
# application.yml
# HikariCP configuration optimized for Virtual Threads
spring:
  datasource:
    hikari:
      # More connections since Virtual Threads allow more concurrency
      maximum-pool-size: 50
      minimum-idle: 10
      # Shorter timeout due to more concurrent requests
      connection-timeout: 5000
      # Fast validation
      validation-timeout: 3000

  # Redis with Lettuce - already async-friendly
  data:
    redis:
      lettuce:
        pool:
          max-active: 50
          max-idle: 20
ConnectionPoolMonitor.javajava
// Pool monitoring to avoid contention
@Component
public class ConnectionPoolMonitor {

    private final HikariDataSource dataSource;

    @Scheduled(fixedRate = 10000)
    public void logPoolStats() {
        HikariPoolMXBean pool = dataSource.getHikariPoolMXBean();
        log.info("Pool stats - Active: {}, Idle: {}, Waiting: {}",
            pool.getActiveConnections(),
            pool.getIdleConnections(),
            pool.getThreadsAwaitingConnection());

        // Alert if too many threads waiting
        if (pool.getThreadsAwaitingConnection() > 100) {
            log.warn("Connection pool contention detected!");
        }
    }
}

Havuz boyutu Virtual Thread sayısına değil veritabanı kapasitesine bağlıdır. Standart bir PostgreSQL yaklaşık 100-200 aktif bağlantıyı destekler.

Soru 9: Virtual Threads etkisi Micrometer ile nasıl ölçülür?

Micrometer ve Spring Boot Actuator, Virtual Threads'in etkinliğini değerlendirmek için temel metrikler sağlar. Bu metrikler kazançları doğrular ve potansiyel sorunları açığa çıkarır.

VirtualThreadMetrics.javajava
// Custom metrics for Virtual Threads
@Component
public class VirtualThreadMetrics {

    private final MeterRegistry registry;
    private final AtomicLong activeVirtualThreads = new AtomicLong(0);

    @PostConstruct
    public void registerMetrics() {
        // Active Virtual Threads counter
        Gauge.builder("virtual.threads.active", activeVirtualThreads, AtomicLong::get)
            .description("Number of active virtual threads")
            .register(registry);

        // JVM metrics for carriers
        Gauge.builder("virtual.threads.carriers", this::getCarrierCount)
            .description("Number of carrier threads")
            .register(registry);
    }

    private double getCarrierCount() {
        // Gets the ForkJoinPool carrier count
        return ForkJoinPool.commonPool().getPoolSize();
    }

    // Interceptor to trace requests
    public void trackVirtualThread(Runnable task) {
        activeVirtualThreads.incrementAndGet();
        try {
            task.run();
        } finally {
            activeVirtualThreads.decrementAndGet();
        }
    }
}
yaml
# application.yml
# Metrics exposure
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,prometheus
  metrics:
    tags:
      application: ${spring.application.name}

Metriklerin analizi Virtual Threads / Carriers oranını ortaya koyar ve bağlantı havuzundaki çekişme dönemlerini saptar.

Geçiş ve Uyumluluk

Soru 10: Hangi kütüphaneler Virtual Threads ile uyumludur?

Uyumluluk, synchronized bloklarının ve yerel çağrıların kullanımına bağlıdır. Spring ekosistemi büyük ölçüde uyumludur, ancak bazı kütüphaneler belirli sürümler gerektirir.

CompatibilityCheck.javajava
// Checking dependency compatibility
@Configuration
public class CompatibilityCheck {

    // Compatible libraries (recommended versions)
    // - Spring Boot 3.2+ (native support)
    // - HikariCP 5.1+ (ReentrantLock instead of synchronized)
    // - Lettuce 6.3+ (non-blocking I/O)
    // - Jackson 2.16+ (no synchronized)

    // Libraries requiring attention
    // - JDBC drivers: check version
    // - Some legacy HTTP clients

    @Bean
    public CommandLineRunner checkCompatibility() {
        return args -> {
            // Log versions for audit
            log.info("Java version: {}", System.getProperty("java.version"));
            log.info("Virtual threads available: {}",
                Thread.ofVirtual() != null);

            // Support verification
            if (Runtime.version().feature() < 21) {
                throw new IllegalStateException(
                    "Java 21+ required for Virtual Threads");
            }
        };
    }
}

Mevcut çoğu modern framework ReentrantLock'a geçmiştir. Eski bağımlılıklar için -Djdk.tracePinnedThreads=short ile yapılan yük testi pinning sorunlarını ortaya çıkarır.

Soru 11: Virtual Threads'e nasıl aşamalı olarak geçilir?

Aşamalı geçiş, üretimi riske atmadan kazançları doğrulamayı ve sorunları tespit etmeyi sağlar. Önerilen strateji, Virtual Threads endpoint'lerini geleneksel olanlardan ayırır.

DualExecutorConfig.javajava
// Configuration for progressive migration
@Configuration
public class DualExecutorConfig {

    // Traditional executor for legacy endpoints
    @Bean("platformExecutor")
    public ExecutorService platformExecutor() {
        return Executors.newFixedThreadPool(200);
    }

    // Virtual Threads executor for new endpoints
    @Bean("virtualExecutor")
    public ExecutorService virtualExecutor() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
}

@RestController
@RequestMapping("/api/v2")
public class MigratedController {

    @Qualifier("virtualExecutor")
    private final ExecutorService executor;

    // Endpoint migrated to Virtual Threads
    @GetMapping("/users/{id}")
    public CompletableFuture<User> getUser(@PathVariable Long id) {
        return CompletableFuture.supplyAsync(() -> {
            // Business code unchanged
            return userService.findById(id);
        }, executor);
    }
}
yaml
# application.yml
# Feature flag for migration
features:
  virtual-threads:
    enabled: true
    endpoints:
      - /api/v2/**
      - /api/reports/**

# Disable for quick rollback
# features.virtual-threads.enabled: false
Dikkat

Tüm bağımlılıkları test etmeden Virtual Threads'i global olarak etkinleştirmemek gerekir. Pinning performansı önemli ölçüde düşürebilir.

Soru 12: Üretime almadan önce hangi testler yapılmalıdır?

Virtual Threads doğrulaması yük testleri, pinning testleri ve uyumluluk testleri gerektirir. Bu testlerin gerçekçi üretim koşullarını taklit etmesi şarttır.

VirtualThreadLoadTest.javajava
// Load test with JUnit and Virtual Threads
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class VirtualThreadLoadTest {

    @LocalServerPort
    private int port;

    @Test
    void shouldHandleHighConcurrency() throws Exception {
        int concurrentRequests = 5000;
        CountDownLatch latch = new CountDownLatch(concurrentRequests);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger errorCount = new AtomicInteger(0);

        HttpClient client = HttpClient.newHttpClient();

        // Launch 5000 simultaneous requests
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < concurrentRequests; i++) {
                executor.submit(() -> {
                    try {
                        HttpRequest request = HttpRequest.newBuilder()
                            .uri(URI.create("http://localhost:" + port + "/api/test"))
                            .build();

                        HttpResponse<String> response = client.send(
                            request, BodyHandlers.ofString());

                        if (response.statusCode() == 200) {
                            successCount.incrementAndGet();
                        } else {
                            errorCount.incrementAndGet();
                        }
                    } catch (Exception e) {
                        errorCount.incrementAndGet();
                    } finally {
                        latch.countDown();
                    }
                });
            }
        }

        latch.await(60, TimeUnit.SECONDS);

        // Performance assertions
        assertThat(successCount.get()).isGreaterThan(4900); // >98% success
        assertThat(errorCount.get()).isLessThan(100);
    }
}

Testler çekişme senaryolarını (doymuş bağlantı havuzu), zaman aşımlarını ve dakikalarca süren sürdürülmüş yükü kapsamalıdır.

İleri Seviye Sorular

Soru 13: Virtual Threads ile Structured Concurrency nasıl etkileşir?

Structured Concurrency (JEP 453) eşzamanlı görevlerin aynı yaşam döngüsünü paylaşmasını sağlayarak Virtual Threads'i tamamlar. Bu yaklaşım hata yönetimini ve iptal işlemlerini kolaylaştırır.

StructuredConcurrencyExample.javajava
// Combining Virtual Threads + Structured Concurrency
public class StructuredConcurrencyExample {

    public UserDashboard fetchDashboard(Long userId) throws Exception {
        // StructuredTaskScope ensures all tasks complete together
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {

            // Three parallel tasks on Virtual Threads
            Subtask<UserProfile> profileTask = scope.fork(() ->
                userService.getProfile(userId));

            Subtask<List<Notification>> notifTask = scope.fork(() ->
                notificationService.getRecent(userId));

            Subtask<AccountBalance> balanceTask = scope.fork(() ->
                accountService.getBalance(userId));

            // Wait for all tasks or fail on first error
            scope.join();
            scope.throwIfFailed();

            // All tasks succeeded - safe aggregation
            return new UserDashboard(
                profileTask.get(),
                notifTask.get(),
                balanceTask.get()
            );
        }
        // If one task fails, others are automatically cancelled
    }
}

Structured Concurrency thread sızıntılarını engeller ve hata ayıklamayı kolaylaştırır; çünkü çağrı yığını kodun mantıksal yapısını yansıtır.

Soru 14: Virtual Threads ile reaktif programlama arasındaki fark nedir?

Her iki yaklaşım da aynı sorunu (I/O verimliliği) çözer ancak farklı programlama modelleri kullanır. Virtual Threads klasik imperatif kod yazmaya izin verirken reaktif yaklaşım stream'ler şeklinde yeniden yazımı zorunlu kılar.

ComparisonService.javajava
// Same logic: imperative vs reactive
@Service
public class ComparisonService {

    // VIRTUAL THREADS APPROACH: classic imperative code
    // Easy to read, debug, and maintain
    public UserData getUserDataImperative(Long id) {
        User user = userRepository.findById(id).orElseThrow();
        List<Order> orders = orderRepository.findByUserId(id);
        PaymentInfo payment = paymentService.getInfo(id);

        return new UserData(user, orders, payment);
    }

    // REACTIVE APPROACH: streams and operators
    // More complex but native backpressure
    public Mono<UserData> getUserDataReactive(Long id) {
        return userRepository.findById(id)
            .zipWith(orderRepository.findByUserId(id).collectList())
            .zipWith(paymentService.getInfo(id))
            .map(tuple -> new UserData(
                tuple.getT1().getT1(),
                tuple.getT1().getT2(),
                tuple.getT2()
            ));
    }
}

| Kriter | Virtual Threads | Reaktif | |--------|-----------------|---------| | Öğrenme eğrisi | Düşük | Yüksek | | Hata ayıklama | Klasik stack trace | Karmaşık | | Backpressure | Manuel | Yerel | | Ekosistem | Büyüyen | Olgun | | Eski kod geçişi | Basit | Yeniden yazma |

Yeni uygulamalar ve göçler için Virtual Threads önerilir. Reaktif programlama, gelişmiş backpressure gerektiren senaryolarda hâlâ değerlidir.

Soru 15: ThreadLocal Virtual Threads ile nasıl yönetilir?

ThreadLocal Virtual Threads ile çalışır, ancak her örnek için bellek tüketir. Scoped Values (JEP 446) bağlam paylaşımı için daha verimli bir alternatif sunar.

ThreadLocalVsScopedValue.javajava
// Comparing context approaches
public class ThreadLocalVsScopedValue {

    // CLASSIC APPROACH: ThreadLocal
    // Works but expensive with millions of VT
    private static final ThreadLocal<RequestContext> requestContext =
        new ThreadLocal<>();

    public void processWithThreadLocal(Request request) {
        requestContext.set(new RequestContext(request.getTraceId()));
        try {
            // Context accessible everywhere in the thread
            processRequest();
        } finally {
            requestContext.remove(); // Important to prevent leaks
        }
    }

    // MODERN APPROACH: ScopedValue (Java 21+)
    // More efficient, immutable, explicit scope
    private static final ScopedValue<RequestContext> CONTEXT =
        ScopedValue.newInstance();

    public void processWithScopedValue(Request request) {
        ScopedValue.where(CONTEXT, new RequestContext(request.getTraceId()))
            .run(() -> {
                // Context accessible within this scope
                processRequest();
                // No cleanup needed - automatic at scope end
            });
    }

    private void processRequest() {
        // Context access
        String traceId = CONTEXT.isBound()
            ? CONTEXT.get().getTraceId()
            : "unknown";
        log.info("Processing with trace: {}", traceId);
    }
}

Yeni geliştirmeler için ScopedValues önerilir. ThreadLocal kullanan eski kod için aşamalı geçiş yapmak makuldür.

Spring Boot mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Sonuç

Virtual Threads, basit ve yüksek performanslı kod yazımına olanak tanıyarak Java backend geliştirmesini dönüştürür. Önemli noktalar:

Temeller:

  • Etkinleştirme: spring.threads.virtual.enabled=true
  • I/O ağırlıklı yükler için ideal (REST, BD, dosyalar)
  • Yoğun CPU hesaplamaları için kaçınılmalı

Performans:

  • Bağlantı havuzlarını doğru boyutlandırın (yeni darboğaz)
  • Pinning'i -Djdk.tracePinnedThreads ile izleyin
  • synchronizedReentrantLock'a taşıyın

Geçiş:

  • Endpoint grupları halinde aşamalı test edin
  • Bağımlılıkların uyumluluğunu doğrulayın
  • Paralel işlemler için Structured Concurrency'yi kullanın

Virtual Threads bilgisi, modern uygulamaların performans zorluklarını anlayan adayları öne çıkarır. Bu kavramlar artık Spring Boot teknik mülakatlarında vazgeçilmezdir.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#spring boot
#virtual threads
#java 21
#project loom
#performance

Paylaş

İlgili makaleler