Java8并⾏流⾃定义线程池
上海世博会主题>电脑显卡排行⽬录
前⾔
Java 8引⼊了并⾏流(Parallel Streams),流会⾃动通过⼀个通⽤的Fork/Join池并⾏地执⾏,这个通⽤Fork/Join池可以使⽤Pool()来访问。
默认并发数不靠谱
高中黑板报通常的通⽤池的期望并发数的默认值是Runtime().availableProcessors() -1,也就是逻辑CPU核⼼数减去1。根据《Java并发编程实战》作者 Brian Goetz所指出的,“虚拟机其实不清楚什么是处理器,它只是去请求操作系统返回⼀个值。同样的,操作系统也不知道怎么回事,它是去问的硬件设备。硬件会告诉它⼀个值,通常来说是硬件线程数。操作系统相信硬件说的,⽽虚拟机⼜相信操作系统说的。”根据Runtime().availableProcessors() 返回的值并不⼀定能创建出合适数量的⼯作线程。如果在同⼀机器上运⾏着多个 JVM,则应限制这个线程数,以防这些 JVM 彼此争⽤ CPU。设置通⽤ Fork/Join池的⼤⼩和设置其他任何线程池同样重要。启动的时候,可以通过系统属性 parallelism来设置通⽤池的并发数。如下,设置线程数4,在笔者6核⼼12线程的CPU上⾯打印为4。
大树的英语
jvm参数:-parallelism=4
魔芋的功效System.out.Pool().getParallelism());
打印:4
通⽤池耗尽
⼀旦这个通⽤池到达了期望并发数的上限,被其他资源占⽤尽,它就不会再创建新的线程了。尽管可能有很多任务正在等待。这样的话,可能会导致严重的性能瓶颈!⽐如两个并⾏流使⽤相同的线程池,会因为相互等待⽽被阻塞,这种情形下并⾏流stream().parallel()还不如普通顺序执⾏来得快。
⾃定义线程池
既然通⽤Fork/Join池有这么多问题,我们可以使⽤⾃定义线程池来避免。通过创建⾃⼰的线程池,避免共享线程池,如果有需要,甚⾄可以分配⽐处理机数量更多的线程。如下代码展⽰了并⾏流如何结合⾃定义线程池。
贡饭
//创建⼀个线程数为2的线程池
ForkJoinPool forkJoinPool = new ForkJoinPool(2);
//在⾃定义线程池⾥⾯实现并⾏计算质数,省略了PrimesPrint::isPrime源码法人授权书模板
forkJoinPool.submit(() ->
洋葱模型
//parallel task here, for example
IntStream.range(1, 1_000_000).parallel().filter(PrimesPrint::isPrime).collect(toList())
).get();