Việc làm

18/09 · Hồ Chí Minh · Tại văn phòng

Backend Dev (Java, Microservices, Spring Boot, Docker)

ATOMI DIGITAL · Backend Developer

Xem mô tả & ứng tuyển trên ITviecMô tả công việc, lương và ứng tuyển nằm ở ITviec.

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, DevOps & CI/CD, System Design & Kiến trúc). 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.

  1. 01So sánh synchronized, volatile, ReentrantLock và ConcurrentHashMap. Bạn tránh race condition thế nào?Java · Senior

    Gợi ý trả lời

    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àm count++ thành atomic.
    • synchronized: vừa loại trừ lẫn nhau vừa đảm bảo visibility (quan hệ happens-before).
    • ReentrantLock: như synchronized nhưng có tryLock với timeout, lock có thể ngắt, nhiều Condition.
    • AtomicInteger/LongAdder: đếm không cần lock.
    • ConcurrentHashMap: thread-safe với độ tranh chấp thấp. Dùng compute/merge/putIfAbsent cho thao tác kép, đừng get rồi put.

    Hay sai: dùng Collections.synchronizedMap rồi duyệt map mà không lock, hoặc kiểm tra if (!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).

    Ôn thêm câu hỏi Java →
  2. 02Mộ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

    Đi từ số liệu đến bằng chứng, đừng đoán rồi sửa.

    1. Xem metrics (Actuator, Micrometer): latency, số request, heap, GC pause, connection pool đang chờ, thời gian gọi DB và API ngoài.
    2. CPU cao: lấy thread dump vài lần cách nhau vài giây (jcmd <pid> Thread.print hoặc jstack), 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.
    3. Chậm mà CPU thấp: thread đang chờ: hết connection DB, lock, gọi API ngoài không có timeout.
    4. 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.
    5. 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.

    Ôn thêm câu hỏi Java →
  3. 03Hai 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

    Đâ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ện where version = ?; nếu người khác đã sửa trước, bạn nhận OptimisticLockException và có thể retry hoặc báo lỗi. Hợp khi tranh chấp ít.
    • Pessimistic locking: @Lock(LockModeType.PESSIMISTIC_WRITE) sinh SELECT ... 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 synchronized trong 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.

    Ôn thêm câu hỏi Java →
  4. 04SLI, SLO và error budget là gì? Bạn đặt alert dựa trên chúng thế nào?DevOps & CI/CD · Senior

    Gợi ý trả lời

    SLI là chỉ số đo trải nghiệm người dùng (tỷ lệ request thành công, độ trễ p99); SLO là mục tiêu cho SLI đó trong một khoảng thời gian; error budget là phần được phép hỏng còn lại.

    • Ví dụ: SLO 99.9% request thành công trong 30 ngày, nghĩa là budget 0.1% request lỗi.
    • Alert theo burn rate: budget đang bị tiêu nhanh bất thường (đo trên cửa sổ ngắn và dài) thì báo, thay vì báo mỗi khi CPU cao.
    • Hết budget: ưu tiên việc ổn định, chậm lại tính năng mới.

    Hay sai: đặt alert trên nguyên nhân (CPU, RAM) thay vì triệu chứng người dùng thấy, dẫn đến báo động giả và mệt mỏi vì alert.

    Ôn thêm câu hỏi DevOps & CI/CD →
  5. 05GitOps là gì? Bạn tổ chức repo và quy trình deploy cho nhiều môi trường, nhiều service ra sao?DevOps & CI/CD · Senior

    Gợi ý trả lời

    GitOps coi Git là nguồn sự thật cho trạng thái hệ thống; một agent trong cluster (Argo CD, Flux) liên tục kéo và đồng bộ, thay vì CI đẩy thẳng bằng kubectl.

    • Tách repo code ứng dụng và repo cấu hình deploy; CI build image rồi mở PR cập nhật tag.
    • Cấu hình dùng chung bằng Helm chart hoặc Kustomize, overlay riêng cho dev/staging/prod.
    • Lên prod qua PR có review; rollback bằng git revert.
    • Bật phát hiện drift và tự sửa lệch cấu hình.
    • CI không cần giữ credential admin của cluster.

    Người phỏng vấn muốn nghe: cân nhắc được đánh đổi, ví dụ secret vẫn cần giải pháp riêng và số lượng PR cập nhật tag có thể nhiều.

    Ôn thêm câu hỏi DevOps & CI/CD →
  6. 06Là kiến trúc sư, bạn đưa ra và ghi lại một quyết định kiến trúc quan trọng như thế nào?System Design & Kiến trúc · Senior

    Gợi ý trả lời

    Quyết định kiến trúc là chọn trade-off dựa trên ràng buộc thực tế (nghiệp vụ, đội ngũ, ngân sách, thời gian), không phải chọn công nghệ "tốt nhất".

    • Xác định các thuộc tính chất lượng quan trọng nhất (hiệu năng, sẵn sàng, bảo mật, chi phí, khả năng thay đổi) và sắp xếp ưu tiên cùng stakeholder.
    • Đưa ra 2–3 phương án, so sánh rủi ro; làm POC hoặc spike cho điểm chưa chắc chắn.
    • Ghi lại bằng ADR (Architecture Decision Record): bối cảnh, quyết định, phương án đã loại, hệ quả. Lưu cùng repo để người sau hiểu "vì sao".
    • Phân biệt quyết định khó đảo ngược (chọn DB, ranh giới service) với quyết định dễ thay đổi; quyết định dễ đảo ngược thì nên làm nhanh.
    • Xem lại quyết định khi bối cảnh thay đổi.

    Người phỏng vấn muốn nghe: bạn thuyết phục đội ngũ bằng dữ liệu, lắng nghe phản biện, và kể được một quyết định từng sai cùng cách bạn sửa.

    Ôn thêm câu hỏi System Design & Kiến trúc →
  7. 07Phân biệt == và equals(). Vì sao override equals() thì phải override cả hashCode()?Java · Junior

    Gợi ý trả lời

    == so sánh tham chiếu (hai biến có trỏ cùng một object không), còn equals() so sánh nội dung theo logic bạn định nghĩa.

    • Hợp đồng: hai object equals nhau thì bắt buộc có cùng hashCode.
    • HashMap/HashSet dùng hashCode để chọn bucket trước, rồi mới dùng equals để so trong bucket. Nếu chỉ override equals, hai object "bằng nhau" có thể rơi vào hai bucket khác nhau, nên set.contains(x) trả về false dù đã add.
    • Với Java 16+, record tự sinh equals/hashCode/toString theo các field.

    Hay sai: so sánh String hoặc Integer bằng ==. Nó có thể chạy đúng nhờ string pool hoặc cache Integer từ -128 đến 127, rồi sai với giá trị khác.

    Ôn thêm câu hỏi Java →
  8. 08Vì sao String là immutable? Khi nào dùng StringBuilder thay cho String?Java · Junior

    Gợi ý trả lời

    String bất biến: mọi thao tác "sửa" đều tạo object mới. Nhờ vậy nó an toàn khi chia sẻ giữa nhiều thread, dùng làm key cho HashMap được (hash không đổi) và JVM có thể dùng chung qua string pool.

    • Nối chuỗi trong vòng lặp bằng + tạo nhiều object trung gian, nên dùng StringBuilder:
    var sb = new StringBuilder();
    for (String s : items) sb.append(s).append(',');
    String result = sb.toString();
    
    • StringBuffer giống StringBuilder nhưng các method có synchronized, chậm hơn và hiếm khi cần.
    • Nối vài chuỗi trên một dòng thì cứ dùng +, compiler đã tối ưu sẵn.

    Người phỏng vấn muốn nghe: bạn hiểu lý do thiết kế (an toàn, hash, pool), không chỉ thuộc định nghĩa.

    Ôn thêm câu hỏi Java →
  9. 09Checked exception và unchecked exception khác nhau thế nào? try-with-resources dùng để làm gì?Java · Junior

    Gợi ý trả lời

    Checked exception (kế thừa Exception nhưng không phải RuntimeException) bị compiler bắt buộc phải catch hoặc khai báo throws, ví dụ IOException. Unchecked (RuntimeException và con của nó) thì không, ví dụ NullPointerException, IllegalArgumentException.

    • Checked hợp với lỗi bên ngoài mà caller có thể xử lý được; unchecked thường là lỗi lập trình hoặc vi phạm điều kiện.
    • try-with-resources tự gọi close() cho mọi object implement AutoCloseable, kể cả khi có exception:
    try (var reader = Files.newBufferedReader(path)) {
        return reader.readLine();
    }
    

    Hay sai: catch (Exception e) {} rồi bỏ trống, làm mất dấu lỗi. Ít nhất phải log kèm stack trace, hoặc bọc lại thành exception có ý nghĩa và ném tiếp.

    Ôn thêm câu hỏi Java →
  10. 10Mức lương mong muốn của bạn là bao nhiêu?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Tìm hiểu trước mặt bằng lương cho vị trí và số năm kinh nghiệm (dữ liệu lương trên Drama Công Ty, bạn bè cùng ngành), rồi đưa ra một khoảng có căn cứ.

    • Nói rõ gross hay net. Gross là lương trước khi trừ bảo hiểm bắt buộc và thuế thu nhập cá nhân; net là số thực nhận.
    • Hỏi tổng thu nhập: lương tháng 13 (không bắt buộc theo luật), thưởng, chu kỳ review lương, bảo hiểm sức khoẻ.
    • Lương thử việc theo luật tối thiểu bằng 85% lương chính thức; nhiều công ty trả 100%, cứ hỏi rõ.

    Câu mẫu: "Dựa trên kinh nghiệm và mặt bằng thị trường, em mong muốn khoảng X đến Y triệu gross. Em cũng muốn hiểu thêm về thưởng và review lương bên mình."

    Hay sai: nói "tuỳ công ty" (dễ bị trả thấp), hoặc khai khống lương hiện tại.

    Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →

Bạn đã phỏng vấn ở ATOMI DIGITAL?

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