Czy można bezpiecznie używać tej samej instancji Random
do generowania strumienia (lub strumienia równoległego) i wpływania na ten strumień w jednej z jego części?IntStream z losowej i losowej współbieżności
Weź pod uwagę poniższy kod. Ten sam gen
jest używany do generowania równoległego IntStream
i generowania losowej przestrzeni co kilka znaków. Działa i kończy się pomyślnie, żaden wyjątek nie został zgłoszony.
Ale czy ten wątek kodu jest bezpieczny? Wygląda na to, ponieważ nie ma niepoprawnych (poza zakresem) wartości znaków. Myślę, że powinienem uszkodzić wewnętrzne dane Random
, ponieważ jego metody nie są oznaczone jako synchronized
, ale najwyraźniej tak nie jest. Czemu?
public class RandomGenTest {
Random gen = new Random();
String getRandomText(int len, double spaceProb) {
return gen.ints(len, 'a', 'z'+1)
.map(i-> gen.nextDouble()<spaceProb?' ':i)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
}
@Test
public void test() {
for (int a=10000; a<10000000; a*=2) {
String text = getRandomText(a, .2);
Assert.assertTrue(text.chars().allMatch(c -> (c>='a' && c<='z') || c==' '));
}
}
}
Należy zauważyć, że użycie 'ograniczenia' w strumieniu równoległym jest receptą na awarię wydajności. I to jest niepotrzebne tutaj, ponieważ możesz użyć ['gen.ints (len, 'a', 'z')'] (http://docs.oracle.com/javase/8/docs/api/java/util/ Random.html # ints-long-int-int-) do skonstruowania skończonego strumienia w pierwszej kolejności. Co więcej, jawne tworzenie nowych obiektów za pomocą 'nowej postaci' jest niepotrzebne, możesz pozwolić, aby autoboxing zrobił coś słusznego. Ale kiedy zmienisz pierwszy 'StringBuilder :: append' na' StringBuilder :: appendCodePoint', nie potrzebujesz w ogóle boxingu, ale możesz po prostu wykonać wszystko używając 'IntStream'. – Holger
Nawiasem mówiąc, granica jest * wyłączna *, więc jeśli chcesz włączyć '' z'', musisz użyć '' z '+ 1' jako związanego. → 'gen.int (len, 'a', 'z' + 1) .parallel(). Map (i -> gen.nextDouble()
Holger
Przy okazji, możesz również uprościć swoje twierdzenie:' Assert.assertTrue (text.chars(). allMatch (c -> (c> = 'a' && c <= 'z') || c == '')); 'który jest taki sam jak' Assert.assertTrue (text.matches ("[az] *")); '(z spacją po' z ') – Holger