实例来自Java中线程池,你真的会用吗?
public class ExecutorsDemo {
private static ExecutorService executorService = Executors.newFixedThreadPool(15);
public static void main(String[] args) {
for (int i=0; i<Integer.MAX_VALUE; i++){
executorService.execute(new SubTread());
}
}
}
在下图中配置实验参数,执行后报内存溢出,Executors创建的线程池存在OOM的风险是因为newFixedThreadPool中创建LinkedBlockingQueue时,并未指定容量。此时,LinkedBlockingQueue就是一个无边界队列,对于一个无边界队列来说,是可以不断的向队列中加入任务的,这种情况下就有可能因为任务过多而导致内存溢出问题。
C:\Users\DELL>jstat -gcutil 5500
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 100.00 99.40 70.09 70.38 2 0.277 62 16.282 16.560
换一种写法,队列满了跑出异常,不会内存溢出。
C:\Users\DELL>jstat -gcutil 22036
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 98.44 93.82 6.53 61.95 78.59 1 0.001 0 0.000 0.001
正在运行的maxinumPoolSize的10个+ArrayBlockingQueue中的10个,加起来20个,就拒绝了。
使用guava来创建,更加清晰,因为可以自己定义名字
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
public class ExecutorsDemo {
private static ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("dzm-%d").build();
private static ExecutorService executorService = new ThreadPoolExecutor(5, 200,
6L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1024),
threadFactory,
new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
for (int i=0; i<Integer.MAX_VALUE; i++){
System.out.println(i);
executorService.execute(new SubTread());
}
}
}
public class SubTread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
//do nothing
}
}
}
这里调整了keepAliveTime
可以S0增加。
C:\Users\DELL>jstat -gcutil 24396
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 81.25 8.70 66.33 95.81 92.32 27 0.021 0 0.000 0.021
C:\Users\DELL>jps
14560 ExecutorsDemo
21136 Jps
25616 RemoteMavenServer36
27696 Main
1432 KotlinCompileDaemon
22076 Launcher
2268 Launcher
26172
C:\Users\DELL>jstat -gcutil 14560
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
98.45 0.00 60.20 11.16 82.57 85.60 2 0.002 0 0.000 0.002
因为增加了线程的名字,所以可以方便定位问题。
待续中。。。