JavaRush /Java Blog /Random-ID /Teori probabilitas dalam praktiknya atau tahukah Anda ten...
Viacheslav
Level 3

Teori probabilitas dalam praktiknya atau tahukah Anda tentang Random

Dipublikasikan di grup Random-ID
Teori probabilitas dalam praktiknya atau yang anda ketahui tentang Random - 1

Perkenalan

Ada banyak ilmu di dunia yang mempelajari teori probabilitas. Dan ilmu pengetahuan terdiri dari berbagai bagian. Misalnya, dalam matematika ada bagian terpisah yang dikhususkan untuk mempelajari kejadian acak, besaran, dll. Namun sains tidak dianggap enteng. Dalam hal ini, teori probabilitas mulai terbentuk ketika orang mencoba memahami pola apa saja yang ada dalam pelemparan dadu saat memainkan permainan untung-untungan. Jika dicermati, ada banyak hal yang tampaknya acak di sekitar kita. Namun segala sesuatu yang acak tidak sepenuhnya acak. Tapi lebih dari itu nanti. Bahasa pemrograman Java juga memiliki dukungan untuk angka acak, dimulai dengan JDK versi pertama. Angka acak di Java dapat digunakan menggunakan kelas java.util.Random . Untuk pengujian, kami akan menggunakan compiler java online tutorialspoint . Berikut adalah contoh primitif penggunaan Random untuk meniru pelemparan “dadu”, atau kubus dalam bahasa Rusia:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        Random rnd = new Random();
        int number = rnd.nextInt(6) + 1;
        System.out.println("Random number: " + number);
    }
}
Tampaknya ini bisa menjadi akhir dari deskripsi Random , tapi tidak sesederhana itu. Mari kita buka deskripsi kelas java.util.Random di Java API. Dan di sini kita melihat hal-hal menarik. Kelas Random menggunakan bilangan pseudo-acak. Bagaimana? Ternyata angka acak tidak begitu acak?
Teori probabilitas dalam praktiknya atau tahukah Anda tentang Acak - 2

Keacakan semu java.util.Random

Dokumentasi untuk kelas java.util.Random mengatakan bahwa jika instance Random dibuat dengan parameter seed yang sama dan urutan tindakan yang sama dilakukan pada instance tersebut, maka instance tersebut akan mengembalikan urutan angka yang identik. Dan jika kita melihat lebih dekat, kita dapat melihat bahwa Random sebenarnya memiliki konstruktor yang mengambil nilai long sebagai sebuah seed:
Random rnd1 = new Random(1L);
Random rnd2 = new Random(1L);
boolean test = rnd1.nextInt(6) == rnd2.nextInt(6);
System.out.println("Test: " + test);
Contoh ini akan mengembalikan nilai true karena benih dari kedua contoh itu sama. Apa yang harus dilakukan? Konstruktor default memecahkan sebagian masalah. Di bawah ini adalah contoh isi konstruktor Random :
public Random() {
	this(seedUniquifier() ^ System.nanoTime());
}
Konstruktor default menggunakan operasi OR eksklusif bitwise . Dan untuk ini menggunakan long yang mewakili waktu saat ini dan beberapa seed :
private static long seedUniquifier() {
	for (;;) {
		long current = seedUniquifier.get();
		long next = current * 181783497276652981L;
		if (seedUniquifier.compareAndSet(current, next))
			return next;
	}
}
Hal menarik lainnya di sini adalah setiap panggilan ke metode pengambil seedUniquifier mengubah nilai seedUniquifier . Artinya, kelas dirancang untuk memilih nomor acak seefisien mungkin. Namun, seperti yang disebutkan dalam dokumentasi, mereka " tidak aman secara kriptografis ". Artinya, untuk beberapa tujuan penggunaan untuk tujuan kriptografi (pembuatan kata sandi, dll.) tidak cocok, karena urutan dengan pendekatan yang tepat diprediksi. Ada contoh topik ini di Internet, misalnya di sini: “ Memprediksi Math.random() berikutnya di Java ”. Atau misalnya source codenya disini: “ Kerentanan Kripto Lemah ”. java.util.Random (pembuat nomor acak) memiliki “jalan pintas” tertentu, yaitu versi singkat dari panggilan yang dijalankan melalui Math.random:
public static void main(String []args){
	int random_number = 1 + (int) (Math.random() * 6);
	System.out.println("Value: " + random_number);
}
Tetapi jika Anda perhatikan lebih dekat, Random yang sama ada di dalamnya:
public static double random() {
	return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
	static final Random randomNumberGenerator = new Random();
}
JavaDoc menyarankan penggunaan kelas SecureRandom untuk " generator nomor pseudo-acak yang aman secara kriptografis ".
Teori probabilitas dalam praktiknya atau yang anda ketahui tentang Random - 3

Amankan Java Acak

Kelas SecureRandom adalah subkelas dari java.util.Random dan terletak di paket java.security . Perbandingan kedua kelas ini dapat dibaca pada artikel “ Perbedaan Java.util.Random dan Java.security.SecureRandom ”. Mengapa SecureRandom ini begitu bagus? Faktanya adalah baginya sumber bilangan acak adalah hal yang terdengar ajaib seperti “kumpulan entropi inti”. Ini merupakan plus dan minus. Kekurangannya bisa anda baca pada artikel : “ Bahaya java.security.SecureRandom ”. Singkatnya, Linux memiliki generator nomor acak kernel (RNG). RNG menghasilkan angka acak berdasarkan data dari kumpulan entropi, yang diisi berdasarkan kejadian acak dalam sistem, seperti pengaturan waktu keyboard dan disk, pergerakan mouse, interupsi, dan lalu lintas jaringan. Informasi lebih lanjut mengenai entropy pool dijelaskan pada materi " Angka acak di Linux (RNG) atau cara "mengisi" /dev/random dan /dev/urandom ". Pada sistem Windows, SHA1PRNG digunakan, diimplementasikan di sun.security.provider.SecureRandom. Dengan berkembangnya Java, SecureRandom juga mengalami perubahan, yang patut dibaca di ulasan “ Pembaruan Java SecureRandom per April 2016 ” untuk gambaran lengkapnya.
Teori probabilitas dalam praktiknya atau yang anda ketahui tentang Random - 4

Multithreading atau menjadi seperti Caesar

Jika Anda melihat kode kelas Random , sepertinya tidak ada yang menunjukkan masalah. Metode tidak ditandai disinkronkan . Tapi ada satu TAPI: saat membuat Random dengan konstruktor default di beberapa thread, kita akan berbagi seed instance yang sama di antara mereka , yang dengannya Random akan dibuat . Dan juga ketika nomor acak baru diterima, AtomicLong internal instance juga berubah . Di satu sisi, tidak ada yang salah dengan hal ini dari sudut pandang logis, karena... AtomicLong digunakan . Di sisi lain, Anda harus membayar segalanya, termasuk produktivitas. Dan untuk ini juga. Oleh karena itu, bahkan dokumentasi resmi untuk java.util.Random mengatakan: " Instance dari java.util.Random adalah threadsafe. Namun, penggunaan instance java.util.Random yang sama secara bersamaan di seluruh thread mungkin akan menemui pertentangan dan akibatnya kinerja yang buruk. Pertimbangkan alih-alih menggunakan ThreadLocalRandom dalam desain multithread ". Artinya, pada aplikasi multi-threaded saat aktif menggunakan Random dari beberapa thread, lebih baik menggunakan kelas ThreadLocalRandom . Penggunaannya sedikit berbeda dari Random biasa :
public static void main(String []args){
	int rand = ThreadLocalRandom.current().nextInt(1,7);
	System.out.println("Value: " + rand);
}
Seperti yang Anda lihat, kami tidak menentukan benih untuk itu . Contoh ini dijelaskan dalam tutorial resmi dari Oracle: Concurrent Random Numbers . Anda dapat membaca lebih lanjut tentang kelas ini di ulasan: " Panduan ThreadLocalRandom di Java ".
Teori probabilitas dalam praktek atau yang anda ketahui tentang Random - 5

StreamAPI dan Acak

Dengan dirilisnya Java 8, kami memiliki banyak fitur baru. Termasuk API Aliran. Dan perubahan tersebut juga mempengaruhi pembentukan nilai Random . Misalnya, kelas Random memiliki metode baru yang memungkinkan Anda mendapatkan Stream dengan nilai acak seperti int, doubleatau long. Misalnya:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        new Random().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
Ada juga kelas baru SplittableRandom :
import java.util.SplittableRandom;

public class HelloWorld{
    public static void main(String []args){
        new SplittableRandom().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
Anda dapat membaca lebih lanjut tentang perbedaan antara SplittableRandom dan kelas lainnya di sini: " Berbagai cara membuat angka Acak di Java ".

Kesimpulan

Saya pikir ada baiknya menarik kesimpulan. Anda perlu membaca JavaDoc dengan cermat untuk kelas yang digunakan. Di balik sesuatu yang sekilas sederhana seperti Random, ada nuansa yang bisa memainkan lelucon yang kejam. #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION