Có hợp lệ để chia sẻ một phiên bản của Random
lớp giữa nhiều luồng không? Và để gọi nextInt(int)
từ nhiều chủ đề cụ thể?
java.util.concurrent.ThreadLocalRandom
.
Có hợp lệ để chia sẻ một phiên bản của Random
lớp giữa nhiều luồng không? Và để gọi nextInt(int)
từ nhiều chủ đề cụ thể?
java.util.concurrent.ThreadLocalRandom
.
Câu trả lời:
Nó là một chuỗi an toàn theo nghĩa nó sẽ vẫn tạo ra các số ngẫu nhiên khi được sử dụng bởi nhiều chủ đề.
Việc triển khai Sun / Oracle JVM sử dụng đồng bộ hóa và AtomicLong làm hạt giống để cải thiện tính nhất quán giữa các luồng. Nhưng nó dường như không được đảm bảo trên tất cả các nền tảng trong tài liệu.
Tôi sẽ không viết chương trình của bạn để yêu cầu đảm bảo như vậy, đặc biệt là khi bạn không thể xác định thứ tự nextInt()
sẽ được gọi.
Nó là chủ đề an toàn, mặc dù nó không phải lúc nào cũng vậy.
Xem http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 để biết thêm chi tiết.
Theo tài liệu, Math.random () đảm bảo rằng nó an toàn cho nhiều luồng sử dụng. Nhưng lớp Random thì không. Tôi giả sử rằng bạn sẽ phải tự đồng bộ hóa điều đó.
Có, Ngẫu nhiên là chủ đề an toàn. các nextInt()
phương pháp gọi là bảo vệ next(int)
phương pháp mà sử dụng AtomicLong seed, nextseed
(nguyên tử dài) để tạo ra một hạt giống tiếp theo. AtomicLong
được sử dụng để đảm bảo an toàn cho sợi khi tạo hạt.
Như đã nói, nó là lưu chủ đề, nhưng nó có thể là khôn ngoan khi sử dụng java.util.concurrent.ThreadLocalRandom
theo bài viết này (liên kết chết). ThreadLocalRandom cũng là một lớp con của Random, vì vậy nó tương thích ngược.
Bài báo hình liên kết nào so sánh profiling kết quả của lớp Random khác nhau:
java.util.Random
,java.util.concurrent.ThreadLocalRandom
vàjava.lang.ThreadLocal<java.util.Random>
. Kết quả cho thấy rằng việc sử dụng ThreadLocalRandom là hiệu quả nhất, tiếp theo là ThreadLocal và bản thân Random hoạt động kém nhất.
Không có lý do gì nhiều chủ đề không thể sử dụng cùng một Ngẫu nhiên. Tuy nhiên, vì lớp không an toàn theo luồng rõ ràng và duy trì một chuỗi các số giả ngẫu nhiên thông qua hạt giống. Nhiều chủ đề có thể kết thúc với cùng một số ngẫu nhiên. Sẽ tốt hơn nếu tạo nhiều Ngẫu nhiên cho mỗi chủ đề và gieo chúng theo cách khác nhau.
CHỈNH SỬA : Tôi vừa nhận thấy rằng việc triển khai Sun sử dụng AtomicLong nên tôi đoán rằng điều đó là an toàn cho Thread (như Peter Lawrey đã lưu ý (+1)).
EDIT2 : OpenJDK cũng sử dụng AtomicLong cho hạt giống. Như những người khác đã nói mặc dù vẫn không tốt nếu dựa vào điều này.
Đây là cách tôi xử lý vấn đề mà không giả định rằng Random sử dụng các biến nguyên tử. Nó vẫn có thể va chạm ngẫu nhiên nếu currentTime * thread id
bằng nhau vào một thời điểm nào đó trong tương lai, nhưng điều đó đủ hiếm đối với nhu cầu của tôi. Để thực sự tránh được khả năng xảy ra va chạm, bạn có thể yêu cầu mỗi yêu cầu chờ một dấu thời gian đồng hồ duy nhất.
/**
* Thread-specific random number generators. Each is seeded with the thread
* ID, so the sequence of pseudo-random numbers are unique between threads.
*/
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random(
System.currentTimeMillis() *
Thread.currentThread().getId());
}
};
(24*60*60*1000)
một phần đáng kể?
(24*60*60*1000)
là để một luồng có ID 12
ở xxxxxxxxxx045
mili không bị bắt giống như một luồng 22
ở xxxxxxxxxx035
mili. Tuy nhiên, tôi không có bất kỳ lý do chính đáng nào để cho rằng ID chuỗi ngày càng tăng và không có lý do chính đáng để nghĩ rằng ngày mai tôi đang tạo chuỗi vào những thời điểm ngẫu nhiên hơn hôm nay. Tôi đã đơn giản hóa alg ngay bây giờ và cập nhật mô tả để xác định thiếu sót.
Các Random
lớp học không được thiết lập cho một trường hợp được sử dụng trong nhiều chủ đề. Tất nhiên, nếu bạn đã làm điều này, có khả năng bạn sẽ tăng khả năng nhận được những con số ngẫu nhiên không thể đoán trước và gần hơn . Nhưng vì nó là một trình tạo giả ngẫu nhiên, tôi không thể hiểu tại sao bạn cần chia sẻ một phiên bản. Có yêu cầu cụ thể hơn không?