2014-04-30 23 views
17

Các trường hợp của java.util.Random là chủ đề an toàn. Tuy nhiên, việc sử dụng đồng thời cùng một phiên bản java.util.Random trên các chủ đề có thể gặp phải tình trạng tranh chấp và hậu quả kém. Thay vào đó, hãy xem xét sử dụng ThreadLocalRandom trong các thiết kế đa luồng.Ngẫu nhiên trên ThreadLocalRandom

Loại tranh chấp nào và do đó hiệu suất kém? Ai có thể làm ơn, giải thích cho tôi ở đây không? Tôi không biết thuật toán nào nằm bên trong Random và ThreadLocalRandom khiến chúng khác nhau.

Trả lời

19

này có thể giúp một chút:

http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html


Trích dẫn từ nguồn:

Thông thường để tạo ra các số ngẫu nhiên, một trong hai chúng tôi Tạo một thể hiện của java.util. Random OR Math.random() - trong đó tạo ra một cá thể của java.util.Random trên lời gọi đầu tiên. Tuy nhiên, việc sử dụng ứng dụng đồng thời ở trên dẫn đến các vấn đề tranh chấp

Ngẫu nhiên là chủ đề an toàn cho nhiều chủ đề sử dụng. Nhưng nếu nhiều chủ đề sử dụng cùng một thể hiện của Random, cùng một hạt giống được chia sẻ bởi nhiều luồng. Nó dẫn đến tranh chấp giữa nhiều chủ đề và do đó để giảm hiệu suất.

ThreadLocalRandom là giải pháp cho vấn đề trên. ThreadLocalRandom có ​​một trường hợp ngẫu nhiên cho mỗi chủ đề và các biện pháp bảo vệ chống lại tranh chấp.


Vì vậy, về cơ bản, sử dụng một trường hợp ngẫu nhiên cho mỗi thread cho phép bạn ngăn chặn đồng bộ hóa trên hạt giống mà phải được sử dụng bởi tất cả các chủ đề.

+0

Nếu tôi tạo một thể hiện mới của java.util.Random trong mỗi chuỗi, nó sẽ không dẫn đến hiệu ứng giống như sử dụng ThreadLocalRandom trong mỗi luồng không? Hoặc làm tất cả các trường hợp của java.util.Random sử dụng cùng một hạt giống? – Peter

+1

Một phần của vấn đề với 'Ngẫu nhiên' là không cần thiết' đồng bộ hóa '; ngay cả khi bạn tạo một chuỗi cho mỗi luồng, nó sẽ không được thực hiện như 'ThreadLocalRandom'. – dimo414

0

Vâng, nếu bạn sử dụng cùng một cấu trúc dữ liệu qua nhiều luồng, nó thường được đồng bộ hóa. Điều này là tốn kém và cần thời gian. ThreadLocalRandom không cần được đồng bộ vì nó chỉ được sử dụng bởi một luồng.

0

Từ Document ThreadLocalRandom API

A random number generator isolated to the current thread. Like the 
* global {@link java.util.Random} generator used by the {@link 
* java.lang.Math} class, a {@code ThreadLocalRandom} is initialized 
* with an internally generated seed that may not otherwise be 
* modified. When applicable, use of {@code ThreadLocalRandom} rather 
* than shared {@code Random} objects in concurrent programs will 
* typically encounter much less overhead and contention. Use of 
* {@code ThreadLocalRandom} is particularly appropriate when multiple 
* tasks (for example, each a {@link ForkJoinTask}) use random numbers 
* in parallel in thread pools. 

ngẫu nhiên có thể được tạo ra nhiều lần/cùng Object ngẫu nhiên sẽ chia sẻ cho nhiều chủ đề (do sự an toàn để sử dụng thực tế). Việc bao giờ tạo nhiều truy cập tài nguyên/cùng một tài nguyên bằng nhiều luồng sẽ gây ra chi phí.

Thay vì tạo cá thể trên mỗi luồng và duy trì tài nguyên trong ThreadLocal sẽ hoàn hảo hơn. vì cá thể không được chia sẻ qua nhiều Chủ đề. và không có nhà xây dựng công cộng, bạn nên sử dụng phương pháp nhà máy để có được nó.

Tôi có thể nói, đó chỉ là Nhà máy của các đối tượng ngẫu nhiên duy trì/lưu trữ cá thể mỗi chủ đề.

0

Một trường hợp ngẫu nhiên chỉ có thể cung cấp số ngẫu nhiên cho một chuỗi tại một thời điểm. Vì vậy, nếu bạn có nhiều chủ đề đồng thời yêu cầu số ngẫu nhiên từ trường hợp đó, có xu hướng làm chậm tất cả các chủ đề.

Mặt khác, mỗi chuỗi sẽ có một cá thể ThreadLocalRandom riêng, do đó không có chuỗi nào bị chặn khi yêu cầu một số ngẫu nhiên.

1

Các thuật toán chính về cơ bản giống nhau. ThreadLocalRandom sử dụng cấu trúc Java ThreadLocal để tạo một biến ngẫu nhiên mới cho mỗi luồng. Điều này đảm bảo rằng các cuộc gọi từ mỗi thread sẽ không bao giờ xung đột với mỗi (không tranh chấp).

Hãy nhìn vào dòng này từ ngẫu nhiên để so sánh:

} while (!seed.compareAndSet(oldseed, nextseed)); 

Khi bạn yêu cầu một giá trị tới, ngẫu nhiên có giá trị cũ và tạo ra một giá trị mới. Sau đó, nó sử dụng hàm AtomicLong.compareAndSet để đặt giá trị mới, chỉ khi giá trị cũ vẫn là giá trị được sử dụng. Nếu một luồng khác đã thay đổi giá trị, vòng lặp sẽ chạy lại (và một lần nữa, cho đến khi nó là vòng lặp duy nhất vừa nhận được vừa thiết lập giá trị trong một thế hệ số ngẫu nhiên). Vì vậy, có thể tranh chấp, và do đó có thể có hiệu quả tác động.

ThreadLocalRandom, bởi vì nó được đảm bảo không xung đột, không yêu cầu chức năng nguyên tử và thao tác/khóa an toàn chỉ.

Có một số sự cân bằng mà bạn muốn suy nghĩ. Sử dụng một Random cho phép một bộ tạo số ngẫu nhiên rất hữu ích nếu bạn muốn sử dụng một hạt giống duy nhất cho ứng dụng của bạn. Nếu bạn thỉnh thoảng thực hiện các cuộc gọi ngẫu nhiên, để xung đột có thể là "hiếm" (không phải trường hợp bình thường) thì bạn có thể không lo lắng về xung đột và tác động nhỏ đến hiệu suất có thể không quan trọng. Nếu bạn đang gọi ngẫu nhiên hàng trăm thời gian mỗi giây trên nhiều luồng, thì bạn rõ ràng muốn sử dụng ThreadLocalRandom.

1

Có một số vấn đề với ThreadLocalRandom, rằng bạn không thể kiểm soát hạt giống ban đầu. Tôi cũng không tìm thấy một phương pháp hạt giống đặt làm việc ở đâu đó. Cần lưu ý rằng có sự tranh chấp khi có nhiều chủ đề sử dụng Math.random(), vì chúng sẽ được truy cập mui xe một cá thể chia sẻ của lớp Random, có một cách khác để sử dụng ThreadLocalRandom cũng giải quyết được vấn đề hạt giống.

ThreadLocalRandom sử dụng hạt giống được lưu trữ vào Chủ đề. Và họ đã quyết định để làm hạt giống ban đầu cho bạn, mà không có bất kỳ phương tiện để kiểm soát nó. Bạn cũng có thể tạo ra trường hợp ngẫu nhiên của riêng bạn và sử dụng nó theo kiểu địa phương . Vì vậy, nếu bạn làm như sau:

/* my thread */ 
rnd = new Random(my_seed); 
/* use rnd */ 

Bạn cũng sẽ không thấy tranh chấp. Và sử dụng cùng một hạt giống, bạn sẽ nhận được có thể tái tạo chuỗi ngẫu nhiên, có thể giúp kiểm tra. Khi bạn có nhiều chủ đề bạn có thể phân phối hạt giống trên các chủ đề này. Nên có các thuật toán xung quanh để tạo ra các hạt khoảng cách tốt.