2009-08-16 39 views
14

tôi sử dụng java.text.NumberFormat đơn giản để chuyển đổi số thành Strings dễ đọc hơn, bằng dấu phẩy tách hàng ngàn, vv Về cơ bản tôi xác định nó như:Java: Sự cố đồng bộ hóa với NumberFormat?

public static NumberFormat nf = NumberFormat.getInstance(Locale.US); 

... và sau đó tôi chỉ cần gọi nf.format (some_number) trong bất kỳ chủ đề nào mà tôi muốn tạo một phiên bản có thể đọc được của một số. Nhưng nhìn vào JavaDoc, nó nói: "Định dạng số thường không được đồng bộ hóa. Chúng tôi khuyên bạn nên tạo các cá thể định dạng riêng biệt cho mỗi chuỗi. Nếu nhiều chủ đề truy cập một định dạng đồng thời, nó phải được đồng bộ hóa bên ngoài."

Nếu tôi chỉ sử dụng phương thức định dạng (số) của đối tượng NumberFormat, có thể nào có vấn đề về đồng bộ hóa không? Tôi đã thử bằng cách sử dụng NumberFormat.getInstance (Locale.US) .format (number) thay vào đó, nhưng có chi phí liên quan đến việc đó mỗi khi tôi cảm thấy có lẽ không thực sự cần thiết. Điều này thực sự cần đồng bộ hóa bên ngoài? Hoặc là có một cách đơn giản hơn, hiệu quả để hoàn thành điều tương tự mà không có NumberFormat?

Cảm ơn!

Trả lời

15

Ngay cả khi định dạng là phương pháp duy nhất bạn từng gọi, nó vẫn không an toàn với luồng. Trong thực tế, chúng tôi đã có lỗi tại nơi làm việc do điều này. Chúng ta thường tạo ra các đối tượng NumberFormat khi đang bay, hoặc sử dụng một ThreadLocal như Gerco đề xuất. Nếu bạn muốn có được ưa thích, bạn có thể phân lớp NumberFormat và trong phương pháp định dạng, hoặc đồng bộ hóa trước khi gọi định dạng trên một số đại biểu NumberFormat hoặc sử dụng một ThreadLocal để lấy một đại biểu.

Tuy nhiên, tôi tin rằng cách đơn giản nhất, đặc biệt là nếu bạn định định dạng/phân tích cú pháp một số số liên tiếp, hãy sử dụng ThreadLocal theo cách thủ công.

+0

Đo lường điều này bằng cách sử dụng https://gist.github.com/jontejj/5430320, kết quả được xuất bản tại http://1.microbenchmarks.appspot.com/run/[email protected]/se.softhouse .common.numbers.NumberFormatBenchmark mức tăng là thực sự khá đáng kể nếu định dạng số là điều duy nhất xảy ra. Điều này mặc dù NumberFormat giữ một bộ nhớ cache cho các trình định dạng được tạo ra và chỉ sao chép chúng trước khi trả về chúng. – jontejj

+0

Và cùng áp dụng cho tất cả các lớp con .. Đặc biệt DateFormat – Snicolas

8

Sử dụng một ThreadLocal <NumberFormat>. Bằng cách đó, mỗi luồng sẽ có cá thể NumberFormat riêng của nó và sẽ không cần phải đồng bộ hóa và chỉ chi phí tối thiểu.

1

Không có lý do gì để chia sẻ đối tượng NumberFormat. Có, nó có thể có vấn đề đồng bộ hóa (xem nguồn cho ngôn ngữ của bạn và bạn sẽ thấy rằng họ sử dụng các biến thành viên, thậm chí để định dạng). Cho đến khi bạn có các vấn đề về hiệu năng (mà bạn rất có thể sẽ không), chỉ cần tạo một vấn đề mới cho mỗi lần sử dụng.

Chỉnh sửa Như Michael Borgwardt chỉ ra, linh cảm của tôi về biến thành viên không chính xác. Tuy nhiên, tại sao phải lo lắng? Sử dụng LocalThread, sao chép NumberFormat, hoặc chỉ cần tạo một cái mới. Hiệu quả về tạo đối tượng không phải là mối quan tâm thực sự hầu hết thời gian (nhưng không phải luôn luôn).

3

Nhìn vào mã nguồn của NumberFormatDecimalFormat, dường như không có trường nào được sử dụng cho kết quả trung gian - vấn đề duy nhất là bản thân định dạng (ví dụ: số chữ số thập phân) có thể thay đổi được chủ đề có thể thay đổi nó trong khi cuộc gọi format() của người khác đang được xử lý và tất nhiên điều đó sẽ dẫn đến một mớ hỗn độn.

Nếu bạn không bao giờ sử dụng bộ định vị, thì nên là OK - nhưng tất nhiên đây chỉ là triển khai hiện tại. Tôi sẽ không cảm thấy thoải mái với tùy thuộc vào điều trái với các tài liệu API. Sử dụng một âm thanh ThreadLocal giống như một sự thỏa hiệp tốt.

+1

Tôi biết đây là câu trả lời cũ, nhưng ... Bạn thực sự không nên đi theo mã nguồn. Ngay cả khi bạn biết bạn đang sử dụng phiên bản Java nào, nó cũng khác nhau giữa các nhà cung cấp. (Tôi đã thấy nhiều sự khác biệt giữa các JVM của IBM và Sun/Oracle chẳng hạn.) –

+0

Trong phiên bản JDK của tôi, thực sự có các kết quả trung gian được lưu trữ, nhưng như bạn đã nói YMMV. – jontejj

2

NumberFormatabstract class. Giá trị mặc định của nó khi gọi getInstance là trả lại phiên bản DecimalFormat.DecimalFormat sử dụng một loạt các trường để duy trì vị trí của nó trong quá trình định dạng, mẫu cho tiền tố và hậu tố, boolean s cho biết có sử dụng ký pháp mũ và hàng nghìn nhóm, int s để mô tả kích thước của các phần nguyên và phân số, v.v.

Tùy chọn ThreadLocal là một cách tuyệt vời để thực hiện nếu bạn mong đợi bất kỳ định dạng đồng thời nào. Lưu ý rằng tất cả các lớp con của lớp abstractFormat được coi là không an toàn cho chuỗi, do đó, ngày định dạng cũng phải được xử lý cẩn thận.

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