2013-06-05 52 views
10

Vì vậy, tôi chỉ cần saw someone try to use một số ThreadLocal<AtomicInteger> trong một số mã Java.
Bây giờ, đối với mã được liên kết, điều đó rõ ràng là vô ích, trong số các vấn đề khác khiến cho yêu cầu bị từ chối.ThreadLocal <AtomicInteger> có thể hữu ích không?

Và có vẻ như nó sẽ luôn vô dụng: AtomicInteger (từ gói java.util.concurrent.atomic) được thiết kế để truy cập đa luồng và ThreadLocal làm cho mỗi chuỗi có giá trị riêng, vậy tại sao lại sử dụng nó?

Câu hỏi của tôi là: Có tình huống nào trong đó ThreadLocal<AtomicInteger> sẽ hữu ích không?

+0

Không phải là một nhận xét thú vị - nhưng tôi thực sự không thể nghĩ ra. Tôi đồng ý với lý do của bạn và nghĩ rằng nó loại trừ mọi tình huống mà ThreadLocal sẽ hữu ích. – selig

+0

Trừ khi sử dụng Reflection, không có cách nào để truy cập vào threadlocal của thread khác. –

Trả lời

6

Vâng, chúng tôi có thể đưa ra một kịch bản hợp pháp:

  1. chúng ta cần một ví dụ thread-địa phương của AtomicInteger lúc bắt đầu mỗi nhiệm vụ;
  2. chúng tôi tiến hành phân phối đối tượng này trong một số chủ đề khác, ví dụ: chủ đề con được chia nhỏ theo chuỗi nhiệm vụ chính.

Nếu không đánh giá tổng thể của ngữ cảnh xuất hiện, chúng tôi không thể đánh giá.

+0

1. Điều này có nghĩa là chúng ta có thể cần phải làm điều đó bởi vì chúng ta có thể cần phải làm điều đó? 2. Nhưng trong bối cảnh này sẽ sử dụng ThreadLocal để bắt đầu với hợp lý. Mặc dù tôi đồng ý rằng rất khó để loại trừ mọi thứ mà không có ngữ cảnh rõ ràng. – selig

+0

@selig Nếu tất cả điều này xảy ra trong mã máy chủ, mỗi yêu cầu của khách hàng được phân tách bằng chuỗi riêng của nó, và luồng chính bắt đầu nhóm chủ đề riêng của nó và phân phối 'AtomicInteger', có thể cần phải được sử dụng lại từ các tác vụ trước đó (nó không phải là một đối tượng mới mỗi lần). Vâng, nó là một căng, nhưng điều đó không quan trọng: một khi bạn có nhu cầu, bạn có nó, và bạn không phạm tội của nó. –

+0

Vâng, điều này nghe có vẻ giống như một kịch bản hợp pháp (máy chủ đa luồng, một luồng/máy khách bàn giao cho nhiều công nhân). Tôi sẽ tiếp tục chấp nhận trong trường hợp có một câu trả lời tốt hơn. – Riking

4

Giả sử chúng ta cần một bộ đếm số nguyên cho mỗi chuỗi. ThreadLocal chỉ có thể làm việc với các đối tượng rất logic chúng ta cần phải sử dụng một int wrapper - Integer

ThreadLocal<Integer> count = new ThreadLocal<>(); 
... 
count.set(count.get() + 1); 

alternatavely chúng ta có thể sử dụng AtomicInteger, không phải vì nó là chủ đề an toàn nhưng vì nó có thể thay đổi

ThreadLocal<AtomicInteger> count = new ThreadLocal<>(); 
... 
count.get().incrementAndGet(); 

Phiên bản 2 có hiệu suất tốt hơn nhiều so với phiên bản 1 là một kẻ giết người thực sự thực sự

+0

Điểm tốt. Tôi sử dụng AtomicReference để truyền một đối tượng kết quả từ mã trong Runnable trở lại người gọi - không phải vì tôi cần atomicity, nhưng vì tôi cần một tham chiếu có thể thay đổi và tôi quá lười biếng để tạo một lớp cho điều đó. – Durandal

+0

Vì vậy, chỉ vì lợi ích của việc có một wrapper tốt bằng văn bản? Có lẽ stdlib nên cung cấp một lớp MutableInteger hoặc một cái gì đó, sau đó. – Riking

+1

'AtomicInteger' sử dụng' volatile' và một số đồng bộ hóa dưới mui xe. Vì vậy, nó không rõ ràng với tôi như thế nào trên cao của nó so sánh với đấm bốc trên không của 'Integer' trong trường hợp này. Bạn đã kiểm tra câu lệnh "phiên bản 1 là một kẻ giết người thực sự hiệu quả" với điểm chuẩn phù hợp chưa? – Vadzim

1

Tôi nghĩ rằng chỉ có những lý do kỳ lạ cho ThreadLocal<AtomicInteger>. Có thể có các tình huống trong đó ThreadLocal không phải là tham chiếu duy nhất cho AtomicInteger để nhiều chủ đề hơn có thể truy cập nó. Khi bạn thấy mình trong một tình huống như vậy, tôi nghĩ rằng bạn tốt hơn có một cái nhìn cẩn thận vào thiết kế của bạn ...

Trong trường hợp bạn làm không cần sự an toàn thread AtomicInteger nhưng chỉ mutability của nó, tôi thích sử dụng một int[] . Ít chi phí hơn sau đó AtomicInteger kết hợp với toàn quyền kiểm soát:

ThreadLocal<int[]> count = new ThreadLocal<>(); 
... 
count.set(new int[1]); 
... 
count.get()[0] = 42; 
... 
count.get()[0] += 4711; 
Các vấn đề liên quan