Việc tạo luồng Java rất tốn kém vì có một chút công việc liên quan:
- Một khối lớn bộ nhớ phải được phân bổ và khởi tạo cho ngăn xếp luồng.
- Các cuộc gọi hệ thống cần được thực hiện để tạo / đăng ký luồng gốc với HĐH máy chủ.
- Các mô tả cần được tạo, khởi tạo và thêm vào các cấu trúc dữ liệu bên trong JVM.
Nó cũng đắt tiền theo nghĩa là sợi chỉ liên kết tài nguyên miễn là nó còn sống; ví dụ ngăn xếp luồng, bất kỳ đối tượng nào có thể truy cập từ ngăn xếp, bộ mô tả luồng JVM, bộ mô tả luồng gốc của hệ điều hành.
Chi phí của tất cả những điều này là cụ thể cho nền tảng, nhưng chúng không hề rẻ trên bất kỳ nền tảng Java nào tôi từng gặp.
Một tìm kiếm của Google đã tìm cho tôi một điểm chuẩn cũ báo cáo tốc độ tạo luồng ~ 4000 mỗi giây trên Sun Java 1.4.1 trên bộ xử lý kép cổ điển 2002 Xeon chạy Linux cổ điển 2002. Một nền tảng hiện đại hơn sẽ cho số lượng tốt hơn ... và tôi không thể nhận xét về phương pháp này ... nhưng ít nhất nó mang lại một sân chơi bóng cho việc tạo ra sợi đắt tiền như thế nào .
Điểm chuẩn của Peter Lawrey chỉ ra rằng việc tạo luồng ngày nay nhanh hơn đáng kể về mặt tuyệt đối, nhưng không rõ mức độ cải thiện này trong Java và / hoặc HĐH ... hoặc tốc độ bộ xử lý cao hơn. Nhưng số của anh ta vẫn chỉ ra sự cải thiện gấp 150 lần nếu bạn sử dụng nhóm luồng so với việc tạo / bắt đầu một luồng mới mỗi lần. (Và anh ấy đưa ra quan điểm rằng tất cả chỉ là tương đối ...)
(Ở trên giả định "các luồng gốc" thay vì "các luồng xanh", nhưng các JVM hiện đại đều sử dụng các luồng gốc vì lý do hiệu năng. Các luồng xanh có thể rẻ hơn để tạo, nhưng bạn phải trả tiền cho các khu vực khác.)
Tôi đã thực hiện một chút đào để xem cách ngăn xếp của một luồng Java thực sự được phân bổ. Trong trường hợp OpenJDK 6 trên Linux, ngăn xếp luồng được phân bổ theo lệnh gọi để pthread_create
tạo luồng gốc. (JVM không vượt qua pthread_create
ngăn xếp preallocated.)
Sau đó, trong pthread_create
ngăn xếp được phân bổ bởi một cuộc gọi mmap
như sau:
mmap(0, attr.__stacksize,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
Theo đó man mmap
, MAP_ANONYMOUS
cờ làm cho bộ nhớ được khởi tạo về không.
Do đó, mặc dù có thể không cần thiết rằng các ngăn xếp luồng Java mới bằng 0 (theo thông số JVM), trong thực tế (ít nhất là với OpenJDK 6 trên Linux), chúng bằng 0.