10 câu hỏi có thể gặp khi phỏng vấn
Chọn theo kỹ năng và cấp của tin (Java, ReactJS, JavaScript & TypeScript). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.
01Bộ nhớ JVM gồm những vùng nào? Garbage Collector hoạt động ra sao và Java có bị memory leak không?Java
Gợi ý trả lời
Ôn thêm câu hỏi Java →Hai vùng chính: stack (mỗi thread một stack, chứa biến cục bộ và tham chiếu) và heap (chứa object, dùng chung). Ngoài ra có Metaspace chứa thông tin class.
- GC tìm các object không còn được tham chiếu từ "GC roots" (biến trên stack, field static...) và thu hồi.
- Heap chia theo thế hệ: object mới nằm ở young generation, sống lâu thì được chuyển lên old generation.
- G1 là GC mặc định; ZGC hợp khi cần pause rất ngắn với heap lớn.
Java vẫn leak khi object không dùng nữa mà vẫn còn tham chiếu:
- Cache hoặc
static Mapchỉ thêm, không bao giờ xoá. ThreadLocalkhôngremove()trong thread pool.- Listener đăng ký mà không huỷ.
Người phỏng vấn muốn nghe: phân biệt được
OutOfMemoryError: Java heap spacevới lỗi Metaspace, và biết dùng heap dump để tìm ai đang giữ object.02Virtual threads trong Java 21 là gì? Khi nào nên dùng và cần lưu ý gì?Java · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Java →Virtual thread là thread nhẹ do JVM quản lý, được gắn lên một số ít platform thread (carrier). Khi gặp I/O blocking, nó nhả carrier để chạy việc khác, nên bạn có thể có hàng trăm nghìn thread mà vẫn viết code blocking dễ đọc.
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { ids.forEach(id -> executor.submit(() -> callApi(id))); }- Hợp với tải nhiều I/O (gọi DB, HTTP). Không giúp gì với tác vụ nặng CPU.
- Spring Boot 3.2+ bật bằng
spring.threads.virtual.enabled=true. - Không đưa virtual thread vào pool: tạo mới cho mỗi task là cách dùng đúng.
- Giới hạn tài nguyên (connection pool DB) vẫn là giới hạn thật; dùng
Semaphorenếu cần. - Trên Java 21, blocking bên trong
synchronizedcó thể "pin" carrier; các bản JDK mới hơn đã cải thiện. Cẩn thận vớiThreadLocalchứa object lớn.
Người phỏng vấn muốn nghe: virtual threads tăng throughput, không làm từng request nhanh hơn.
03So sánh
synchronized,volatile,ReentrantLockvàConcurrentHashMap. Bạn tránh race condition thế nào?Java · SeniorGợi ý trả lời
Ôn thêm câu hỏi Java →Race condition xảy ra khi nhiều thread đọc-sửa-ghi cùng dữ liệu mà không đồng bộ. Mỗi công cụ giải quyết một phần:
volatile: đảm bảo visibility (thread khác thấy giá trị mới nhất), nhưng không làmcount++thành atomic.synchronized: vừa loại trừ lẫn nhau vừa đảm bảo visibility (quan hệ happens-before).ReentrantLock: nhưsynchronizednhưng cótryLockvới timeout, lock có thể ngắt, nhiềuCondition.AtomicInteger/LongAdder: đếm không cần lock.ConcurrentHashMap: thread-safe với độ tranh chấp thấp. Dùngcompute/merge/putIfAbsentcho thao tác kép, đừnggetrồiput.
Hay sai: dùng
Collections.synchronizedMaprồi duyệt map mà không lock, hoặc kiểm traif (!map.containsKey(k)) map.put(k, v)trên map đồng thời: hai bước riêng lẻ vẫn bị chen ngang. Cách tốt nhất vẫn là giảm state dùng chung (object bất biến, mỗi thread một bản).04React Server Components là gì? Trong Next.js App Router, khi nào dùng Server Component và khi nào cần
"use client"?ReactJS · SeniorGợi ý trả lời
Ôn thêm câu hỏi ReactJS →Server Component chạy trên server (lúc build hoặc lúc request), có thể
awaitdữ liệu trực tiếp từ DB hoặc API, và không gửi JavaScript của nó xuống trình duyệt. Trong App Router, component mặc định là Server Component.- Dùng Server Component cho: lấy dữ liệu, render nội dung tĩnh, dùng secret hoặc thư viện nặng chỉ cần ở server.
- Cần
"use client"khi dùng state, effect, sự kiện (onClick), API trình duyệt (window,localStorage). "use client"đánh dấu ranh giới: mọi module được import từ file đó đều vào bundle client.- Server Component có thể truyền Server Component khác vào Client Component qua
children. - Props truyền từ server sang client phải serialize được (không truyền hàm thường; Server Action thì được).
Hay sai: đặt
"use client"ở layout gốc, biến cả app thành client và mất lợi ích. Hãy đẩy phần tương tác xuống các component lá.05Một màn hình React (bảng dữ liệu lớn, ô tìm kiếm) bị giật lag. Bạn tìm và xử lý thế nào?ReactJS · Senior
Gợi ý trả lời
Ôn thêm câu hỏi ReactJS →Đo trước: React DevTools Profiler (bật "Highlight updates" và xem component nào render nhiều, tốn bao lâu) và tab Performance của Chrome để tìm long task.
Các hướng xử lý thường gặp:
- Giảm phạm vi render: đưa state xuống gần nơi dùng; tách component;
memocác hàng của bảng với props ổn định. - Virtualization cho list hoặc bảng dài: chỉ render các dòng đang hiện (TanStack Virtual, react-window).
- Ưu tiên cập nhật:
useDeferredValuehoặcuseTransitionđể ô input phản hồi ngay, còn việc lọc bảng chạy sau và có thể bị ngắt. - Tính toán nặng:
useMemo, hoặc chuyển sang Web Worker. - Bundle lớn:
lazy()vàSuspenseđể tách code theo route hoặc theo modal.
Người phỏng vấn muốn nghe: bạn tìm ra nguyên nhân cụ thể (render thừa, DOM quá nhiều, JS nặng) rồi mới chọn kỹ thuật, không rải
useMemokhắp nơi.- Giảm phạm vi render: đưa state xuống gần nơi dùng; tách component;
06Một trang web dùng càng lâu càng chậm và tốn RAM. Bạn tìm memory leak ở frontend thế nào?JavaScript & TypeScript · Senior
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Memory leak ở frontend thường do thứ gì đó vẫn giữ tham chiếu đến object đáng lẽ đã bỏ đi, nhất là trong SPA vì trang không bao giờ tải lại.
Nguyên nhân hay gặp:
addEventListenertrênwindow/documentmà không gỡ khi component bị huỷ.setInterval, subscription (WebSocket, store) không huỷ.- DOM đã bị gỡ khỏi trang nhưng vẫn được biến JS giữ lại (detached DOM).
- Cache hoặc mảng toàn cục chỉ tăng không giảm.
Cách điều tra với Chrome DevTools:
- Tab Memory: chụp heap snapshot, thực hiện thao tác vài lần, chụp lại, so sánh phần tăng thêm.
- Lọc "Detached" để tìm DOM bị giữ, xem chuỗi retainers để biết ai đang giữ.
- Tab Performance bật Memory để xem heap có giảm sau GC không.
Người phỏng vấn muốn nghe: mỗi tài nguyên đăng ký đều có chỗ huỷ tương ứng (cleanup của effect,
ngOnDestroy,onUnmounted,AbortController).07Một service Spring Boot trên production đột nhiên chậm, CPU cao hoặc bị OOM. Bạn điều tra thế nào?Java · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Java →Đi từ số liệu đến bằng chứng, đừng đoán rồi sửa.
- Xem metrics (Actuator, Micrometer): latency, số request, heap, GC pause, connection pool đang chờ, thời gian gọi DB và API ngoài.
- CPU cao: lấy thread dump vài lần cách nhau vài giây (
jcmd <pid> Thread.printhoặcjstack), tìm thread luôn RUNNABLE ở cùng chỗ. Có thể là vòng lặp, regex xấu, hoặc GC chạy liên tục. - Chậm mà CPU thấp: thread đang chờ: hết connection DB, lock, gọi API ngoài không có timeout.
- OOM hoặc heap tăng dần: bật
-XX:+HeapDumpOnOutOfMemoryError, mở heap dump bằng Eclipse MAT, xem ai giữ nhiều bộ nhớ nhất. - Java Flight Recorder (
jcmd <pid> JFR.start) cho profile chi phí thấp, dùng được trên production.
Người phỏng vấn muốn nghe: có quy trình rõ ràng, biết cả cách giảm thiệt hại tạm thời (rollback, scale) trước khi tìm nguyên nhân gốc.
08Hai người cùng đặt mua sản phẩm cuối cùng trong kho. Bạn xử lý cập nhật đồng thời trong JPA thế nào?Java · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Java →Đây là bài toán lost update. Có hai hướng chính, chọn theo mức độ tranh chấp:
- Optimistic locking: thêm field
@Version. Khi update, Hibernate kèm điều kiệnwhere version = ?; nếu người khác đã sửa trước, bạn nhậnOptimisticLockExceptionvà có thể retry hoặc báo lỗi. Hợp khi tranh chấp ít. - Pessimistic locking:
@Lock(LockModeType.PESSIMISTIC_WRITE)sinhSELECT ... FOR UPDATE, giữ khoá đến hết transaction. Hợp khi tranh chấp nhiều, đổi lại throughput giảm và có nguy cơ deadlock. - Đơn giản nhất cho tồn kho: update có điều kiện ngay trong DB:
UPDATE product SET stock = stock - 1 WHERE id = ? AND stock > 0;Kiểm tra số dòng bị ảnh hưởng: bằng 0 nghĩa là hết hàng.
Hay sai: dùng
synchronizedtrong code Java. Nó vô dụng khi chạy nhiều instance, và cũng không bảo vệ được dữ liệu ở DB.- Optimistic locking: thêm field
09Phân biệt
==vàequals(). Vì sao overrideequals()thì phải override cảhashCode()?Java · JuniorGợi ý trả lời
Ôn thêm câu hỏi Java →==so sánh tham chiếu (hai biến có trỏ cùng một object không), cònequals()so sánh nội dung theo logic bạn định nghĩa.- Hợp đồng: hai object
equalsnhau thì bắt buộc có cùnghashCode. HashMap/HashSetdùnghashCodeđể chọn bucket trước, rồi mới dùngequalsđể so trong bucket. Nếu chỉ overrideequals, hai object "bằng nhau" có thể rơi vào hai bucket khác nhau, nênset.contains(x)trả vềfalsedù đã add.- Với Java 16+,
recordtự sinhequals/hashCode/toStringtheo các field.
Hay sai: so sánh
StringhoặcIntegerbằng==. Nó có thể chạy đúng nhờ string pool hoặc cacheIntegertừ -128 đến 127, rồi sai với giá trị khác.- Hợp đồng: hai object
10Kể về một lần bạn bất đồng với đồng nghiệp hoặc trưởng nhóm. Bạn xử lý thế nào?Câu hỏi hành vi & văn hoá
Gợi ý trả lời
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Dùng STAR: Situation (bối cảnh), Task (nhiệm vụ), Action (bạn làm gì), Result (kết quả). Phần Action nên chiếm nhiều nhất.
Câu mẫu:
- S: "Lead muốn dùng một thư viện mới cho module báo cáo, em thấy thư viện đó còn ít người dùng và lo về bảo trì."
- T: "Em cần nêu rủi ro mà không làm chậm tiến độ."
- A: "Em gặp riêng anh, đưa so sánh hai phương án và đề xuất làm thử một bản nhỏ trong hai ngày để đánh giá."
- R: "Kết quả thử cho thấy thư viện cũ đáp ứng đủ, anh đồng ý giữ lại. Từ đó team có thói quen làm bản thử trước khi đổi công nghệ."
Người phỏng vấn muốn nghe: bạn tranh luận bằng dữ liệu, tôn trọng người khác, và chấp nhận quyết định cuối cùng kể cả khi không theo ý mình.
Bạn đã phỏng vấn ở Nitori Digital Base Vietnam?
Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.
Chia sẻ kinh nghiệm phỏng vấn