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, SQL & Database). 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.
01Virtual 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.
02So 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).03Mộ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.
04Khi nào chọn NoSQL (MongoDB, Redis…) thay vì SQL? Trade-off là gì?SQL & Database · Senior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →Chọn theo mô hình truy cập dữ liệu, không theo xu hướng. SQL mạnh ở quan hệ, ràng buộc và transaction; NoSQL mạnh ở schema linh hoạt, mô hình dữ liệu đặc thù hoặc scale ngang dễ hơn.
- Document (MongoDB): dữ liệu dạng cây, đọc nguyên khối theo một khoá, schema thay đổi thường xuyên.
- Key-value (Redis): cache, session, rate limit, bộ đếm, hàng đợi nhỏ; dữ liệu chủ yếu nằm trong RAM.
- Wide-column, time-series, search engine: ghi khối lượng lớn, log, tìm kiếm full-text.
Trade-off: JOIN và transaction nhiều document hạn chế hoặc đắt hơn, ràng buộc dữ liệu chuyển sang tầng ứng dụng, và phải thiết kế theo query ngay từ đầu.
Người phỏng vấn muốn nghe: nhiều hệ thống dùng kết hợp, vd. PostgreSQL làm nguồn sự thật, Redis làm cache. PostgreSQL với
JSONBcũng đủ cho nhiều nhu cầu "schema linh hoạt".05Bảng có hàng trăm triệu dòng, query ngày càng chậm. Bạn dùng partitioning, sharding hay read replica?SQL & Database · Senior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →Mỗi kỹ thuật giải một vấn đề khác nhau, nên cần xác định điểm nghẽn là đọc, ghi hay kích thước dữ liệu.
- Read replica: giảm tải đọc. Phải chấp nhận replication lag; luồng vừa ghi xong đọc lại nên đọc từ primary.
- Partitioning (trong một DB): chia bảng theo khoảng thời gian hoặc theo key. Query có điều kiện trên partition key chỉ quét phần liên quan, xoá dữ liệu cũ bằng
DROP PARTITIONrất nhanh. - Sharding (nhiều DB): khi một máy không chịu nổi lượng ghi hoặc dung lượng. Đổi lại phải chọn shard key cẩn thận, query xuyên shard và transaction phân tán rất khó.
Thứ tự hợp lý: tối ưu query và index, archive dữ liệu cũ, thêm replica và cache, partition, cuối cùng mới shard.
Hay sai: chọn shard key gây hot spot, vd. theo ngày tạo khiến mọi lượt ghi dồn vào một shard.
06Hai 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
07Dependency Injection trong Spring là gì? Vì sao nên dùng constructor injection thay cho
@Autowiredtrên field?JavaGợi ý trả lời
Ôn thêm câu hỏi Java →IoC container của Spring tạo và quản lý các bean, rồi "tiêm" phụ thuộc vào class cần dùng, thay vì class tự
new. Nhờ vậy code ít phụ thuộc cứng, dễ thay implementation và dễ test.Constructor injection được khuyên dùng vì:
- Field có thể là
final, object luôn ở trạng thái đầy đủ sau khi tạo. - Test unit không cần Spring: chỉ cần
new OrderService(mockRepo). - Constructor quá nhiều tham số là dấu hiệu class đang ôm nhiều việc.
- Class chỉ có một constructor thì không cần ghi
@Autowired.
Nên nói thêm về scope: mặc định bean là
singleton(một instance cho cả context), ngoài ra cóprototype,request,session.Hay sai: để state thay đổi được (ví dụ biến đếm, list) trong bean singleton. Nhiều request chạy song song sẽ dùng chung và gây race condition.
- Field có thể là
08
@Transactionalhoạt động thế nào? Vì sao có lúc gắn annotation rồi mà transaction không chạy?JavaGợi ý trả lời
Ôn thêm câu hỏi Java →Spring tạo proxy bao quanh bean. Khi gọi method có
@Transactionalqua proxy, proxy mở transaction, gọi method thật, rồi commit hoặc rollback.Những lý do hay gặp khiến nó "không ăn":
- Self-invocation: method A trong cùng class gọi
this.b()có@Transactional, lời gọi không đi qua proxy. - Method là
privatehoặcfinal: proxy không chặn được lời gọi. - Mặc định chỉ rollback với unchecked exception và
Error. Checked exception vẫn commit, trừ khi khai báorollbackFor = Exception.class. - Exception bị
catchvà nuốt bên trong method.
Nên biết thêm
propagation(REQUIRED,REQUIRES_NEW) vàreadOnly = truecho các truy vấn chỉ đọc.Người phỏng vấn muốn nghe: bạn giải thích được bằng cơ chế proxy, không chỉ liệt kê lỗi.
- Self-invocation: method A trong cùng class gọi
09Can you tell me a little about yourself?Phỏng vấn tiếng Anh
Gợi ý trả lời
Ôn thêm câu hỏi Phỏng vấn tiếng Anh →"I'm a backend developer with about three years of experience, mostly working with Java and Spring Boot on payment systems. In my current role, I'm responsible for the reconciliation module and I've worked closely with clients in Japan and Singapore. I enjoy solving performance problems and improving code quality. Now I'm looking for a product-focused team where I can grow into system design, which is why this position caught my attention."
Mẹo: giữ khung hiện tại – quá khứ – tương lai, nói khoảng một phút. Dùng "I'm responsible for…", "I've worked on…" thay vì "I am in charge about…". Đừng mở đầu bằng tên trường hay quê quán.
10Điểm yếu của bạn là gì?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á →Chọn điểm yếu thật, không chí mạng với vị trí, và cho thấy bạn đang cải thiện.
Cấu trúc: điểm yếu, ảnh hưởng đã gặp, việc bạn đang làm để khắc phục, tiến bộ đến nay.
Câu mẫu: "Trước đây em hay ngại hỏi khi bị kẹt, tự loay hoay quá lâu, có lần làm trễ task. Giờ em tự đặt giới hạn: kẹt quá một hai giờ mà không có hướng thì em hỏi đồng đội, kèm những gì đã thử. Từ khi làm vậy em xong việc đúng hạn hơn và học được nhanh hơn từ người khác."
Ví dụ khác có thể dùng: chưa quen nói trước đám đông, tiếng Anh nói chưa trôi chảy, hay ôm việc.
Hay sai: "Điểm yếu của em là quá cầu toàn" (nghe như né câu hỏi), hoặc nêu điểm yếu là kỹ năng cốt lõi của vị trí.
Bạn đã phỏng vấn ở Rakuten Fintech Vietnam Co., Ltd.?
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