Panimula
Maraming mga agham sa mundo na nag-aaral ng teorya ng posibilidad. At ang mga agham ay binubuo ng iba't ibang mga seksyon. Halimbawa, sa matematika mayroong isang hiwalay na seksyon na nakatuon sa pag-aaral ng mga random na kaganapan, dami, atbp. Ngunit hindi basta-basta ang agham. Sa kasong ito, nagsimulang mabuo ang teorya ng probabilidad nang sinubukan ng mga tao na maunawaan kung anong mga pattern ang mayroon sa paghagis ng dice kapag naglalaro ng pagkakataon. Kung titingnang mabuti, maraming mga tila random na bagay sa paligid natin. Ngunit ang lahat ng random ay hindi ganap na random. Ngunit higit pa sa na mamaya. Ang Java programming language ay mayroon ding suporta para sa mga random na numero, simula sa unang bersyon ng JDK. Maaaring gamitin ang mga random na numero sa Java gamit ang
java.util.Random na klase . Para sa pagsubok, gagamitin namin
ang tutorialspoint java online compiler . Narito ang isang primitive na halimbawa ng paggamit
ng Random upang tularan ang paghagis ng "dice", o mga cube sa Russian:
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);
}
}
Mukhang ito na ang katapusan ng paglalarawan ng
Random , ngunit hindi ito ganoon kasimple. Buksan natin ang paglalarawan ng
java.util.Random na klase sa Java API. At dito nakikita natin ang mga kawili-wiling bagay.
Ang Random na klase ay gumagamit ng mga pseudo-random na numero. Paano kaya? Ito ay lumiliko na ang mga random na numero ay hindi gaanong random?
Pseudo-randomness java.util.Random
Ang dokumentasyon para sa klase
ng java.util.Random ay nagsasabi na kung ang mga instance
ng Random ay ginawa gamit ang parehong parameter
ng seed at ang parehong mga pagkakasunud-sunod ng mga aksyon ay ginanap sa mga pagkakataon, ibinabalik nila ang magkaparehong pagkakasunud-sunod ng mga numero. At kung titingnan nating mabuti, makikita natin na
ang Random ay talagang mayroong
isang constructor na tumatagal ng ilang
mahabang halaga bilang
isang binhi:
Random rnd1 = new Random(1L);
Random rnd2 = new Random(1L);
boolean test = rnd1.nextInt(6) == rnd2.nextInt(6);
System.out.println("Test: " + test);
Ang halimbawang ito ay babalik
ng totoo dahil
ang binhi ng parehong mga pagkakataon ay pareho. Anong gagawin? Ang default na tagabuo ay bahagyang nalulutas ang problema. Nasa ibaba ang isang halimbawa ng mga nilalaman ng
Random constructor :
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
Ang default na tagabuo ay gumagamit ng bitwise na eksklusibong
OR na operasyon .
At gumagamit ng mahabang kumakatawan sa kasalukuyang oras at ilang
binhi para dito :
private static long seedUniquifier() {
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
Ang isa pang kawili-wiling bagay dito ay ang bawat tawag sa
seedUniquifier getter method ay nagbabago sa halaga
ng seedUniquifier . Iyon ay, ang klase ay idinisenyo upang pumili ng mga random na numero nang mahusay hangga't maaari. Gayunpaman, tulad ng sinasabi ng dokumentasyon, sila
ay "hindi ligtas sa cryptographically ". Iyon ay, para sa ilang layunin ng paggamit para sa cryptographic na layunin (pagbuo ng password, atbp.) hindi ito angkop, dahil hinuhulaan ang pagkakasunod-sunod na may wastong diskarte. May mga halimbawa sa paksang ito sa Internet, halimbawa dito: "
Predicting the next Math.random() in Java ". O halimbawa ang source code dito: "
Vulnerability Weak Crypto ". Ang java.util.Random (random number generator) ay may isang tiyak na "shortcut", iyon ay
, isang pinaikling bersyon ng tawag na isinasagawa sa pamamagitan ng Math.random:
public static void main(String []args){
int random_number = 1 + (int) (Math.random() * 6);
System.out.println("Value: " + random_number);
}
Ngunit kung titingnan mong mabuti, ang parehong Random ay nasa loob:
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
Ang JavaDoc ay nagpapayo sa paggamit
ng SecureRandom class para sa isang "
cryptographically secure pseudo-random number generator ".
Secure Random Java
Ang SecureRandom class ay isang subclass ng
java.util.Random at matatagpuan sa
java.security package . Ang paghahambing ng dalawang klase na ito ay mababasa sa artikulong "
Pagkakaiba sa pagitan ng java.util.Random at java.security.SecureRandom ". Bakit napakahusay ng SecureRandom na ito? Ang katotohanan ay para sa kanya ang pinagmulan ng mga random na numero ay tulad ng isang mahiwagang-tunog na bagay bilang ang "core entropy pool". Ito ay parehong plus at minus. Mababasa mo ang tungkol sa mga disadvantages nito sa artikulong: “
The dangers of java.security.SecureRandom ”. Sa madaling salita, ang Linux ay may kernel random number generator (RNG). Bumubuo ang RNG ng mga random na numero batay sa data mula sa entropy pool, na pinupunan batay sa mga random na kaganapan sa system, tulad ng mga timing ng keyboard at disk, paggalaw ng mouse, mga interrupt, at trapiko sa network. Ang higit pang impormasyon tungkol sa entropy pool ay inilarawan sa materyal na "
Mga random na numero sa Linux (RNG) o kung paano "punan" /dev/random at /dev/urandom ". Sa mga Windows system, ginagamit ang SHA1PRNG, na ipinatupad sa sun.security.provider.SecureRandom. Sa pag-unlad ng Java, nagbago din ang SecureRandom, na sulit na basahin sa pagsusuri na "
Mga update ng Java SecureRandom noong Abril 2016 " para sa isang kumpletong larawan.
Multithreading o maging tulad ni Caesar
Kung titingnan mo ang code ng
Random class , tila walang nagpapahiwatig ng problema. Ang mga pamamaraan ay hindi namarkahang
naka-synchronize . Ngunit may isang PERO: kapag gumagawa ng
Random na may default na constructor sa ilang mga thread, ibabahagi namin ang parehong
instance seed sa pagitan nila , kung saan
ang Random ay gagawin . At kapag may natanggap na bagong random na numero, nagbabago rin ang panloob
na AtomicLong ng instance . Sa isang banda, walang mali dito mula sa lohikal na pananaw, dahil... Ginagamit
ang AtomicLong . Sa kabilang banda, kailangan mong bayaran ang lahat, kabilang ang pagiging produktibo. At para din dito. Samakatuwid, kahit na ang opisyal na dokumentasyon para sa
java.util.Random ay nagsasabing: "
Ang mga pagkakataon ng java.util.Random ay threadsafe. Gayunpaman, ang sabay-sabay na paggamit ng parehong java.util.Random na instance sa mga thread ay maaaring makatagpo ng pagtatalo at kahihinatnang hindi magandang pagganap. Isaalang-alang sa halip ay gumagamit ng ThreadLocalRandom sa mga multithreaded na disenyo ". Iyon ay, sa mga multi-threaded na application kapag aktibong gumagamit ng
Random mula sa ilang mga thread, mas mainam na gamitin ang
ThreadLocalRandom class . Ang paggamit nito ay bahagyang naiiba sa karaniwang
Random :
public static void main(String []args){
int rand = ThreadLocalRandom.current().nextInt(1,7);
System.out.println("Value: " + rand);
}
Gaya ng nakikita mo, hindi kami nagsasaad
ng binhi para dito . Ang halimbawang ito ay inilarawan sa opisyal na tutorial mula sa Oracle:
Concurrent Random Numbers . Maaari mong basahin ang higit pa tungkol sa klase na ito sa pagsusuri: "
Gabay sa ThreadLocalRandom sa Java ".
StreamAPI at Random
Sa paglabas ng Java 8, marami kaming bagong feature. Kasama ang Stream API. At naapektuhan din ng mga pagbabago ang pagbuo ng mga
Random na halaga.
Halimbawa, ang Random na klase ay may mga bagong pamamaraan na nagbibigay-daan sa iyong makakuha
ng Stream na may mga random na halaga tulad ng
int
,
double
o
long
. Halimbawa:
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));
}
}
Mayroon ding bagong klase
na 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));
}
}
Maaari kang magbasa nang higit pa tungkol sa pagkakaiba sa pagitan ng
SplittableRandom at iba pang mga klase dito: "
Iba't ibang paraan upang lumikha ng mga Random na numero sa Java ".
Konklusyon
Sa tingin ko ito ay nagkakahalaga ng pagguhit ng isang konklusyon. Kailangan mong maingat na basahin ang JavaDoc para sa mga klase na ginamit. Sa likod ng isang bagay na kasing simple sa unang tingin gaya ng Random ay may mga nuances na maaaring maglaro ng malupit na biro. #Viacheslav
GO TO FULL VERSION