Bean trong Spring có an toàn cho đa luồng không?

Kết luận: KHÔNG an toàn cho đa luồng

Hệ thống Spring không cung cấp cơ chế bảo vệ đa luồng cho Bean. Tính an toàn của Bean phụ thuộc vào phạm vi (scope) và trạng thái sử dụng:

Các loại phạm vi Bean trong Spring

  1. singleton: Mặc định, chỉ tồn tại một thể hiện duy nhất
  2. prototype: Mỗi yêu cầu tạo ra một thể hiện mới
  3. request: Một thể hiện cho mỗi yêu cầu HTTP
  4. session: Một thể hiện cho mỗi phiên người dùng
  5. global-session: Thể hiện dùng chung cho tất cả phiên

Phân tích theo phạm vi

  • Prototype Bean: Mỗi luồng có một thể hiện riêng → Tự nhiên an toàn
  • Singleton Bean:
    • An toàn khi không có trạng thái (chỉ sử dụng phương thức, không lưu trữ dữ liệu)
    • Dễ xảy ra xung đột khi có trạng thái (sử dụng biến thành viên)

Ví dụ minh họa

@RestController
public class BaoHiemController {
    private int bien = 0;
    
    @GetMapping("/kiem-tra")
    public String kiemTraBien() {
        return "Gia tri bien: " + (++bien);
    }
}

Kết quả khi gọi 3 lần liên tiếp:

Lượt gọiKết quả
1Gia tri bien: 1
2Gia tri bien: 2
3Gia tri bien: 3

Giải pháp bảo vệ đa luồng

  1. Sử dụng @Scope("prototype") cho Bean cần bảo vệ
  2. Tránh biến tĩnh (static) trong Bean
  3. Dùng ThreadLocal để lưu trữ dữ liệu riêng cho từng luồng
  4. Cấu hình phạm vi cho Bean phụ thuộc:
    @Configuration
    public class CauHinh {
        @Bean
        @Scope("prototype")
        public NguoiDung taoNguoiDung() {
            return new NguoiDung();
        }
    }

Thí nghiệm tổng hợp

@RestController
@Scope("singleton")
public class NghiemController {
    private int bien = 0;
    private static int bienDungChung = 0;
    ThreadLocal<Integer> luongRieng = new ThreadLocal<>();

    @Autowired
    private NguoiDung nguoiDung;

    @GetMapping("/kiem-tra-tong-hop")
    public String test() {
        luongRieng.set(1);
        nguoiDung.setTuoi(1);
        return String.format("Bien: %d, BienDungChung: %d, ThreadLocal: %d, NguoiDung: %d",
            ++bien, ++bienDungChung, luongRieng.get(), nguoiDung.getTuoi());
    }
}

Kết quả thử nghiệm:

Yếu tốSingletonPrototype
Biến thườngXung độtAn toàn
Biến staticXung độtXung đột
ThreadLocalAn toànAn toàn
Bean phụ thuộcXung độtAn toàn (khi cấu hình prototype)

Kết luận thực tiễn

  • Tránh dùng biến thành viên trong Bean singleton
  • Ưu tiên thiết kế Bean không trạng thái
  • Chỉ sử dụng ThreadLocal khi cần thiết
  • Cấu hình phạm vi phù hợp cho tất cả Bean trong hệ thống

Thẻ: Spring Framework Bean Scope Thread Safety Dependency Injection Java Concurrency

Đăng vào ngày 22 tháng 5 lúc 02:18