展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

Executor框架

  • 案例1
public class ExecutorDemo {

    public static void main(String[] args) {
        // 方式1
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 方式2,传入参数,线程数量
        ExecutorService executorService1 = Executors.newFixedThreadPool(2);
        // 方式3,传入参数,核心线程数量
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        // 方式4
        ExecutorService executorService2 = Executors.newWorkStealingPool();
        // 方式5
        ExecutorService executorService3 = Executors.newSingleThreadExecutor();
        // 方式6
        ScheduledExecutorService scheduledExecutorService1 = Executors.newSingleThreadScheduledExecutor();

        // 使用方式都是,提交任务到线程池
        executorService.submit(() -> {
            System.out.println(Thread.currentThread().getName());
        });
    }
    
}
  • 简介
newCachedThreadPool:创建一个可以根据需要创建新线程的线程池,如果有空闲线程,优先使用空闲的线程 
# 查看源码
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,    // 核心线程数、最大线程容量
                                      60L, TimeUnit.SECONDS,    // 存活时间60毫秒
                                      new SynchronousQueue<Runnable>());    // 工作队列
    }

newFixedThreadPool:创建一个固定大小的线程池,在任何时候,最多只有N个线程在处理任务 
newScheduledThreadPool:能延迟执行、定时执行的线程池 
newWorkStealingPool:工作窃取,使用多个队列来减少竞争 
newSingleThreadExecutor:单一线程的线程池,只会使用唯一一个线程来执行任务,即使提交再多的任务,也都是会放到等待队列里进行等待 newSingleThreadScheduledExecutor:单线程能延迟执行、定时执行的线程池
  • 线程池的使用建议
尽量避免使用Executor框架创建线程池
    newFixedThreadPool newSingleThreadExecutor 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM 
    newCachedThreadPool newScheduledThreadPool 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM
  • 案例2: 模拟OOM异常
public class OOMDemo {

    public static void main(String[] args) {
        // new 1个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        // 死循环向线程池中提交任务
        while (true) {
            executorService.submit(() -> {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

}
  • 设置VM options



-Xms60m
-Xmx60m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=C:\work
  • 执行结果
# C:\work路径下生成文件

pool-1-thread-1
pool-1-thread-2
java.lang.OutOfMemoryError: Java heap space
Dumping heap to C:\work\java_pid7132.hprof ...
Heap dump file created [113116988 bytes in 0.993 secs]

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "pool-1-thread-1"

Process finished with exit code 1
  • 运行ha456.jar
java -jar ha456.jar

  • 案例3: 模拟OOM异常
# 在限定了堆的内存之后,还会把整个电脑的内存撑爆
# 创建线程时用的内存并不是我们制定jvm堆内存,而是系统的剩余内存

public class OOMDemo2 {

    public static void main(String[] args) {
        // new 1个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (true) {
            executorService.submit(() -> {          // 不断提交任务到线程池
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    
}
  • 线程池使用建议
创建线程池时,核心线程数不要过大
相应的逻辑,发生异常时要处理
submit 如果发生异常,不会立即抛出,而是在get的时候,再抛出异常
execute 直接抛出异常
  • 案例4
public class OOMDemo3 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 100; i++) {
            Future<Integer> submit = executorService.submit(() -> {     // 提交任务到线程池
                System.out.println(Thread.currentThread().getName());
                return 1 / 0;
            });
            submit.get();
        }
    }

}

# 控制台打印结果
pool-1-thread-1
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at com.xdclass.pool.OOMDemo3.main(OOMDemo3.java:22)
Caused by: java.lang.ArithmeticException: / by zero
	at com.xdclass.pool.OOMDemo3.lambda$main$0(OOMDemo3.java:19)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
  • 案例5
public class OOMDemo3 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 100; i++) {
            executorService.execute(() -> {     // 提交任务到线程池
                System.out.println(Thread.currentThread().getName());
                int j=1/0;
            });
        }
    }

}

# 控制台打印结果
pool-1-thread-24
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
	at com.xdclass.pool.OOMDemo3.lambda$main$0(OOMDemo3.java:19)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-3" Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
posted @ 2022-05-16 16:39  DogLeftover  阅读(27)  评论(0)    收藏  举报