Apakah utas kelas acak aman?

110

Apakah valid untuk membagikan satu instance Randomkelas di antara beberapa utas? Dan untuk menelepon nextInt(int)dari beberapa utas secara khusus?

Shcheklein
sumber
@Bala R, tidak, kita tidak berbicara tentang objek Acak C # tetapi Java.
Buhake Sindi
Ups. maaf melewatkan bagian itu.
Bala R
Perawatan menggunakan Random untuk mendapatkan angka di lingkungan multithread dapat memberikan hasil yang buruk. Mungkin tidak masalah tetapi jika Anda melakukan beberapa simulasi, ada baiknya untuk mengetahuinya.
Maxence SCHMITT
14
Untuk pembaca lebih lanjut: ada kelas baru dengan nama 1.7 java.util.concurrent.ThreadLocalRandom.
Jin Kwon

Jawaban:

66

Ini adalah utas aman dalam arti masih akan menghasilkan angka acak saat digunakan oleh banyak utas.

Implementasi Sun / Oracle JVM menggunakan sinkronisasi dan AtomicLong sebagai seed untuk meningkatkan konsistensi di seluruh thread. Namun tampaknya tidak dijamin di semua platform dalam dokumentasi.

Saya tidak akan menulis program Anda untuk meminta jaminan seperti itu, terutama karena Anda tidak dapat menentukan urutan nextInt()pemanggilan.

Peter Lawrey
sumber
69
Jaminan telah ditambahkan di dokumen Java 7: "Contoh java.util.Random aman untuk thread." docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R
8

Menurut dokumentasi, Math.random () menjamin keamanannya untuk digunakan oleh banyak utas. Tetapi kelas Random tidak. Saya berasumsi bahwa Anda harus menyinkronkan itu sendiri.

Vincent Mimoun-Prat
sumber
7

Ya, Acak aman untuk thread. yang nextInt()metode memanggil dilindungi next(int)metode yang menggunakan AtomicLong seed, nextseed(atom panjang) untuk menghasilkan benih berikutnya. AtomicLongdigunakan untuk keamanan benang pada generasi benih.

Buhake Sindi
sumber
6

Seperti yang dikatakan, ini adalah penyimpanan utas, tetapi mungkin bijaksana untuk menggunakan java.util.concurrent.ThreadLocalRandommenurut artikel ini (tautan mati). ThreadLocalRandom juga merupakan subkelas dari Random, sehingga kompatibel dengan versi sebelumnya.

Artikel ini linked dibandingkan profil hasil dari kelas Acak berbeda: java.util.Random, java.util.concurrent.ThreadLocalRandom dan java.lang.ThreadLocal<java.util.Random>. Hasil penelitian menunjukkan, bahwa penggunaan ThreadLocalRandom paling berkinerja, diikuti oleh ThreadLocal dan Random berkinerja terburuk itu sendiri.

seyfahni
sumber
4

Tidak ada alasan mengapa beberapa utas tidak dapat menggunakan semua Acak yang sama. Namun, karena kelas tersebut tidak secara eksplisit aman untuk thread dan mempertahankan urutan nomor pseudo-random melalui seed. Beberapa utas mungkin berakhir dengan nomor acak yang sama. Akan lebih baik untuk membuat beberapa Random untuk setiap utas dan menyemainya secara berbeda.

EDIT : Saya baru saja memperhatikan bahwa implementasi Sun menggunakan AtomicLong jadi saya rasa itu aman untuk Thread (seperti juga dicatat oleh Peter Lawrey (+1)).

EDIT2 : OpenJDK juga menggunakan AtomicLong untuk benih. Seperti yang dikatakan orang lain meskipun masih tidak baik untuk mengandalkan ini.

alpian
sumber
3

Inilah cara saya menangani masalah tanpa mengasumsikan bahwa Random menggunakan variabel atom. Itu masih bisa bertabrakan secara acak jika currentTime * thread idsama di masa depan, tapi itu cukup langka untuk kebutuhan saya. Untuk benar-benar menghindari kemungkinan tabrakan, Anda dapat meminta setiap permintaan menunggu stempel waktu jam yang unik.

/**
 * 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());
    }
};
Ryan
sumber
Naik! T: Apakah (24*60*60*1000)sebagian penting?
Jin Kwon
1
Ya, itu perbaikan kotor. Itu (24*60*60*1000)agar utas dengan ID 12di xxxxxxxxxx045millis tidak diunggulkan sama dengan utas 22di xxxxxxxxxx035millis. Namun, saya tidak memiliki alasan kuat untuk menganggap bahwa ID utas adalah tambahan, dan tidak ada alasan kuat untuk berpikir saya membuat utas pada waktu yang lebih acak besok daripada hari ini. Saya menyederhanakan alg sekarang dan memperbarui deskripsi untuk mengidentifikasi kekurangannya.
Ryan
0

The Randomkelas tidak diatur untuk satu contoh yang akan digunakan dalam beberapa thread. Tentu saja, jika Anda melakukan ini, kemungkinan besar Anda akan meningkatkan kemungkinan menjadi tidak dapat diprediksi dan mendekati angka acak . Tetapi karena ini adalah generator pseudo-random, saya tidak mengerti mengapa Anda perlu membagikan sebuah instance. Apakah ada persyaratan yang lebih spesifik?

Peminum Java
sumber