Topik wawancara representatif

Scoped Values Java 25: Bagaimana Anda Membandingkannya dengan ThreadLocal?

CodingSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Masalah apa yang diselesaikan oleh ScopedValue di Java 25? Bandingkan dengan ThreadLocal dan jelaskan penggunaan yang benar dengan thread pool atau virtual thread.

Perintah dan cakupan

Seorang pewawancara mungkin bertanya: “Masalah apa yang diselesaikan oleh ScopedValue di Java 25? Bandingkan dengan ThreadLocal dan jelaskan penggunaan yang benar dengan thread pool atau virtual thread.”

JEP 506 memfinalisasi Scoped Values di JDK 25. Fitur ini memungkinkan pemanggil berbagi data yang tidak dapat diubah (immutable) dengan pemanggil yang lebih dalam (callees) dan thread anak di dalam cakupan leksikal, sehingga mengurangi kebutuhan untuk meneruskan konteks melalui setiap parameter metode. Pertanyaan ini menguji pemahaman batas masa pakai (lifetime), visibilitas, dan konkurensi; pertanyaan ini tidak terjawab hanya dengan menyebut ScopedValue sebagai “ThreadLocal baru.”

Apa yang diuji oleh pewawancara

  • Apakah Anda memahami ScopedValue sebagai parameter implisit yang immutable dan dikontrol oleh cakupan.
  • Apakah Anda dapat menjelaskan pengikatan (binding) dan pemulihan dari where(...).run(...) atau call(...).
  • Apakah Anda mengenali perbedaan dari ThreadLocal yang mutable, penggunaan kembali thread dalam pool, dan pewarisan pada virtual thread.
  • Apakah Anda mempertimbangkan kontrol akses kunci, jumlah binding, propagasi pengecualian (exception), dan pembatalan (cancellation).
  • Apakah Anda tahu kapan parameter eksplisit atau ThreadLocal tetap sesuai untuk digunakan.

Pertanyaan klarifikasi

  • Apakah nilai yang dibagikan berupa ID permintaan, prinsipal, tenant, atau status transaksi yang dapat diubah (mutable)?
  • Apakah nilai tersebut harus bersifat read-only, dan haruskah tugas anak mewarisinya?
  • Apakah eksekusi dilakukan pada thread platform, virtual thread, konkurensi terstruktur, atau pool yang sudah ada?
  • Mungkinkah kode membaca kunci di luar cakupannya atau mengekspos Carrier ke kode yang tidak tepercaya?
  • Apakah framework bergantung pada pembersihan ThreadLocal, mutasi, atau integrasi MDC?

Jawaban 30 detik

Anda dapat mengatakan:

ScopedValue adalah mekanisme konteks Java 25 yang immutable dan memiliki cakupan leksikal. Pemanggil membuat binding dengan ScopedValue.where(key, value).run(...) atau call(...); binding tersebut dipulihkan ketika cakupan berakhir, dan hanya kode yang memegang kuncinya yang dapat membacanya. Dibandingkan dengan ThreadLocal, fitur ini mengurangi pembersihan pada thread pool dan kebocoran status yang dapat diubah, menjadikannya berguna untuk konteks permintaan, virtual thread, dan konkurensi terstruktur. Fitur ini tidak menggantikan ThreadLocal yang harus diperbarui langkah demi langkah, dan nilainya tidak boleh keluar dari cakupannya. Saya akan menguji pewarisan, pengecualian, pembatalan, dan visibilitas kunci pada JDK target.

Penalaran langkah demi langkah

Memahami model pengikatan (binding model)

Nilai dapat dibaca selama rentang eksekusi dinamis, sementara pengikatannya dibuat eksplisit oleh struktur kode:

java
static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();

ScopedValue.where(REQUEST_ID, "req-42").run(() -> {
    audit("start");
    handleRequest();
});

static void audit(String message) {
    logger.info("{} {}", REQUEST_ID.orElse("missing"), message);
}

audit tidak memerlukan parameter ID permintaan, tetapi metode ini membaca nilai yang bermakna hanya di dalam cakupan binding. Setelah cakupan berakhir, binding tidak dapat mencemari thread pemanggil.

Membandingkan mutabilitas ThreadLocal

ThreadLocal memberi setiap thread nilai yang mutable; penggunaan kembali thread pool memerlukan pembersihan atau permintaan berikutnya dapat melihat konteks basi (stale). ScopedValue dirancang untuk berbagi data immutable, dengan binding bersarang yang untuk sementara membayangi (shadow) nilai luar dan memulihkannya sesudahnya. Ini mengurangi tanggung jawab pembersihan tetapi tidak membawa mesin status yang harus di-set berulang kali oleh kode di tingkat lebih dalam.

Menangani tugas anak dan virtual thread

JEP 506 menargetkan biaya berbagi data yang dapat diprediksi dengan virtual thread dan konkurensi terstruktur. Apakah pewarisan terjadi, kapan data ditangkap, dan bagaimana sebuah executor berperilaku harus diverifikasi terhadap JDK target dan kontrak API; jangan memindahkan asumsi dari thread pool biasa. Objek yang dibagikan harus tetap immutable sehingga sebuah referensi tidak dapat melewati batas konteks.

Merancang kunci, pengecualian, dan kompatibilitas

Jadikan kunci sebagai objek private static final atau bagian dari API yang terkontrol. Jangan memperlakukan kunci yang dibagikan secara global sebagai batas keamanan. Gunakan orElse atau pengecualian eksplisit untuk nilai yang hilang; di Java 25, orElse tidak lagi menerima null. Pengecualian yang keluar dari run atau call tetap keluar dari cakupan dan memulihkan binding luar. Untuk JDK versi lama, pertahankan parameter eksplisit atau implementasi ThreadLocal di balik jalur kompatibilitas yang teruji.

Contoh jawaban berkualitas tinggi

Saya memperlakukan ScopedValue sebagai parameter implisit yang immutable, bukan sebagai pengganti mutable untuk ThreadLocal. Titik masuk permintaan membuat cakupan terstruktur dengan where(key, value).run atau call; metode di tingkat yang lebih dalam membaca ID permintaan, tenant, atau prinsipal melalui kunci, dan binding dipulihkan saat keluar. Ini cocok untuk konteks read-only dalam virtual thread dan konkurensi terstruktur serta menghindari kebocoran pembersihan thread pool. ThreadLocal tetap berguna untuk status yang harus diperbarui langkah demi langkah, dengan pembersihan di blok finally. Saya akan membatasi visibilitas kunci, menguji pewarisan tugas anak, pengecualian, pembatalan, shadowing bersarang, dan pembacaan di luar cakupan, serta mempertahankan implementasi eksplisit atau yang kompatibel untuk JDK versi lama.

Kesalahan umum

  • Menyebut ScopedValue sebagai ThreadLocal mutable dengan pembersihan otomatis.
  • Menyimpan Carrier atau nilai di luar cakupan, atau membaca kunci setelah masa pakainya berakhir.
  • Mengabaikan penggunaan kembali thread pool, pewarisan tugas anak, dan perbedaan virtual thread.
  • Menyimpan objek mutable sambil mengklaim bahwa seluruh konteks bersifat immutable.
  • Berbagi kunci ke modul mana pun secara sembarangan dan salah mengira kontrol akses sebagai enkripsi.
  • Melupakan aturan non-null orElse Java 25 atau menghilangkan jalur untuk JDK versi lama.

Pertanyaan lanjutan dan jawabannya

1. Bisakah ScopedValue menggantikan setiap ThreadLocal?

Tidak. Ini cocok untuk konteks read-only yang terikat cakupan. Status yang harus diperbarui melalui rantai panggilan masih dapat menggunakan ThreadLocal atau parameter eksplisit, dengan tanggung jawab pembersihan yang diperlukan.

2. Apa yang terjadi dengan pengikatan bersarang (nested bindings)?

Cakupan dalam dapat mengikat nilai baru untuk sementara bagi kunci yang sama; keluar dari cakupan tersebut akan memulihkan nilai luar. Jalur pengecualian juga keluar dari cakupan, sehingga nilai dalam tidak bocor ke luar.

3. Bagaimana Anda menguji pewarisan konkuren?

Cakup thread platform, virtual thread, tugas terstruktur, dan penggunaan kembali thread pool. Periksa nilai yang dilihat oleh tugas anak, pembersihan setelah pembatalan, shadowing bersarang, dan pembacaan di luar cakupan. Tetapkan versi JDK dan konfigurasi executor dalam matriks pengujian.

Sumber publik

Pertanyaan terkait

Alat wawancara terkait

Gunakan Tangkapan Layar untuk perintah coding

Ambil tangkapan layar soal, lalu telusuri batasan, solusi, kode, edge case, dan kompleksitas secara berurutan.

Lihat alat