IntStream 来自 Random 和 Random 并发
IntStream from Random and Random concurrency
使用相同的 Random
实例来生成流(或并行流)并影响其中一部分的流是否安全?
考虑下面的代码。相同的 gen
用于生成并行 IntStream
并每隔几个字符生成随机 space。它运行并成功完成,没有抛出异常。
但是这段代码线程安全吗?看起来是这样,因为没有无效(超出范围)的字符值。我想我应该破坏 Random
的内部数据,因为它的方法没有标记为 synchronized
,但显然情况并非如此。为什么?
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==' '));
}
}
}
Random
的Javadoc拼写出来:
Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs.
Random
是一个线程安全对象,因为 AtomicLong
保留当前种子,因此使用它可以逆转大部分并行加速,这是您练习的重点。
而是使用 ThreadLocalRandom.getCurrent()
并至少避免了争用问题(尽管引入了 ThreadLocal
查找的开销)。还可以使用 SplittableRandom
检索外部随机数流。此实现允许随机访问流元素,这是实现良好并行化的关键。
import static java.util.concurrent.ThreadLocalRandom.current;
String getRandomText(int len, double spaceProb) {
return new SplittableRandom().ints(len, 'a', 'z'+1).parallel()
.map(i -> current().nextDouble()<spaceProb ? ' ' : i)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
使用相同的 Random
实例来生成流(或并行流)并影响其中一部分的流是否安全?
考虑下面的代码。相同的 gen
用于生成并行 IntStream
并每隔几个字符生成随机 space。它运行并成功完成,没有抛出异常。
但是这段代码线程安全吗?看起来是这样,因为没有无效(超出范围)的字符值。我想我应该破坏 Random
的内部数据,因为它的方法没有标记为 synchronized
,但显然情况并非如此。为什么?
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==' '));
}
}
}
Random
的Javadoc拼写出来:
Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs.
Random
是一个线程安全对象,因为 AtomicLong
保留当前种子,因此使用它可以逆转大部分并行加速,这是您练习的重点。
而是使用 ThreadLocalRandom.getCurrent()
并至少避免了争用问题(尽管引入了 ThreadLocal
查找的开销)。还可以使用 SplittableRandom
检索外部随机数流。此实现允许随机访问流元素,这是实现良好并行化的关键。
import static java.util.concurrent.ThreadLocalRandom.current;
String getRandomText(int len, double spaceProb) {
return new SplittableRandom().ints(len, 'a', 'z'+1).parallel()
.map(i -> current().nextDouble()<spaceProb ? ' ' : i)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();