2016-10-06 29 views
5

Cho phép lấy SimpleDateFormat làm ví dụ vì nó không phải là chủ đề an toàn.dễ bay hơi vs threadLocal trong java

tôi có thể cho phép mỗi thread để có bản sao riêng của mình SimpleDateFormat sử dụng ThreadLocal như thế này:

private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){ 
    @Override 
    protected SimpleDateFormat initialValue() 
    { 
     return new SimpleDateFormat("yyyyMMdd HHmm"); 
    } 
}; 

Nhưng đảm bảo từ khóa volatile a thread sẽ có các bản sao mới nhất của biến. Vì vậy, tôi không thể làm điều này thay thế:

volatile SimpleDateFormat myformatter; 

và đạt được cùng một chủ đề an toàn?

+1

Vì đó không phải là nơi vấn đề an toàn chủ đề xảy ra: vấn đề an toàn chủ đề là 'SimpleDateFormat' có trạng thái có thể thay đổi, độc lập với việc tham chiếu được lưu trữ trong trường biến động hay không. –

+1

Thread-local và 'volatile' không làm như vậy! Với thread-local, có một bản sao riêng của biến cho mỗi luồng. Với 'volatile', tất cả các luồng chia sẻ một biến. Việc biến biến 'volatile' không làm cho nó an toàn thread, bởi vì' SimpleDateFormat' có trạng thái bên trong mà không được cập nhật bởi nhiều luồng đồng thời, như Andy đã đề cập. – Jesper

Trả lời

4

người nhận bảo lãnh từ khóa volatile a thread sẽ có các bản sao mới nhất của biến

Trong số dễ bay hơi biến chỉ, không lĩnh vực của mình.

Ngoài ra, volatile chỉ hữu ích nếu bạn cần thay đổi giá trị của biến. Trong trường hợp sử dụng của bạn, final vẻ như nó sẽ thích hợp hơn:

private static final SimpleDateFormat format = ... 

này cũng đảm bảo rằng bạn sẽ có giá trị gần đây nhất của biến - bởi vì nó chỉ có thể được gán giá trị của nó một lần, và static final có đảm bảo khả năng hiển thị khi lớp được tải đầy đủ.


Nhưng đây không phải là lý do tại sao SimpleDateFormat không phải là thread an toàn anyway: nó có thể thay đổi trạng thái mà nó sử dụng để lưu trữ các giá trị trung gian khi định dạng ngày tháng.

Nếu một chuỗi gọi format trong khi một luồng khác cũng thuộc phương pháp format cho cùng một ví dụ SimpleDateFormatter, các biến trung gian này bị cản trở không mong muốn, dẫn đến nhiễu giữa chủ đề và do đó không thể đoán trước được.

Không quan trọng giá trị của các biến trung gian này có được cập nhật khi đọc/ghi bởi một luồng khác hay không - việc cập nhật của chúng có thể được xen kẽ.

Tóm lại, volatile không ngăn chặn sự can thiệp của chủ đề và do đó không phải là phương án thay thế thích hợp cho ThreadLocal tại đây.

+1

'Chỉ biến số biến động, không phải các trường của nó.' --- đây thực sự là không chính xác, thậm chí gây hiểu lầm, bởi vì bạn sẽ quan sát tất cả ghi vào các trường của đối tượng được giới thiệu mà luồng đã viết trước khi ghi vào trường' volatile' . Đây là bản chất của ấn phẩm an toàn. –

+0

@MarkoTopolnik thực sự? Những gì tôi nghĩ là một cái gì đó giống như 'System.out.println (volatileField.nonVolatileField);' - đọc của 'volatileField' có thể cung cấp cho bạn khả năng hiển thị của tất cả các ghi để' nonVolatileField' đến thời điểm đó; nhưng không thể 'nonVolatileField' sau đó được cập nhật giữa việc đọc' volatileField' và 'volatileField.nonVolatileField'? –

+0

Vâng, đó là lý do tại sao tôi nói từ ngữ của bạn là "gây hiểu nhầm", không phải "không chính xác". Có vẻ như bạn không nhận được _any_ đảm bảo ngoại trừ chính tham chiếu 'volatile'. Mặt khác, bạn sẽ không đảm bảo việc quan sát trạng thái "gần đây nhất" của trường 'volatile' vì" gần đây nhất "thậm chí không phải là một khái niệm được xác định rõ trong JMM. Sự khác biệt cơ bản là tính nhất quán tuần tự so với tính tuyến tính. –

0

Bạn không đạt được độ an toàn cùng một sợi với volatile vì cùng một ví dụ SimpleDateFormat sẽ được sử dụng trong các luồng khác nhau.

1

ThreadLocal là cơ sở cho phép chủ đề có bản sao cục bộ của riêng mình đối tượng. ThreadLocals được sử dụng tốt nhất với các đối tượng có thể được an toàn trong chính sách an toàn của thread chủ đề an toàn (ngay cả đối với nhiều đối tượng không phải là "an toàn thread", sử dụng an toàn thread vẫn có thể miễn là không có tham chiếu đến chúng rò rỉ ra từ chủ đề hạn chế). ThreadLocals không thể giúp thread sử dụng an toàn cho các đối tượng có thể thay đổi được chia sẻ bên ngoài luồng mà instantiates chúng.

Từ khóa volatile được sử dụng để cung cấp hình thức an toàn chủ đề yếu với biến có thể được truy cập bởi nhiều luồng khác nhau.Điểm khác biệt chính là ThreadLocals thường không được truy cập bởi nhiều hơn một luồng.

Nói chung, an toàn luồng yêu cầu cả hai khả năng hiển thị (các cập nhật mới nhất cho biến sẽ hiển thị với các chủ đề khác) và loại trừ lẫn nhau (chuyển đổi trạng thái phải là nguyên tử để trạng thái không thể quan sát được là không nhất quán). Volatile hoạt động với Mô hình bộ nhớ Java để đảm bảo rằng biến sẽ hiển thị, nhưng nó không cung cấp dạng loại trừ lẫn nhau và do đó không cung cấp nguyên tử cho trạng thái chuyển đổi trong các đối tượng.

volatileThreadLocal rất khác nhau, thực sự không có trường hợp chung nào để bạn có thể thay thế cho người khác.

Các vấn đề liên quan