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
- singleton: Mặc định, chỉ tồn tại một thể hiện duy nhất
- prototype: Mỗi yêu cầu tạo ra một thể hiện mới
- request: Một thể hiện cho mỗi yêu cầu HTTP
- session: Một thể hiện cho mỗi phiên người dùng
- 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ọi | Kết quả |
| 1 | Gia tri bien: 1 |
| 2 | Gia tri bien: 2 |
| 3 | Gia tri bien: 3 |
Giải pháp bảo vệ đa luồng
- Sử dụng @Scope("prototype") cho Bean cần bảo vệ
- Tránh biến tĩnh (static) trong Bean
- Dùng ThreadLocal để lưu trữ dữ liệu riêng cho từng luồng
- 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ố | Singleton | Prototype |
| Biến thường | Xung đột | An toàn |
| Biến static | Xung đột | Xung đột |
| ThreadLocal | An toàn | An toàn |
| Bean phụ thuộc | Xung đột | An 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