当前位置: 首页 > article >正文

线程池遇到未处理的异常会崩溃吗?

线程池中的 executesubmit 方法详解

在这里插入图片描述

目录

  1. 引言
  2. execute 方法
    • 使用示例代码
  3. submit 方法
    • 2.1 提交 Callable 任务
    • 2.2 提交 Runnable 任务
  4. 遇到未处理异常
    • 3.1 execute 方法遇到未处理异常
    • 3.2 submit 方法遇到未处理异常
  5. 小结

引言

在多线程编程中,线程池是提高性能和资源利用率的重要工具。Java 提供了 executesubmit 两种方法来提交任务到线程池。虽然它们看起来相似,但在实际使用中却有显著的区别。本文将详细介绍这两种方法的使用场景及其在处理异常时的行为差异。


execute 方法

execute 方法用于提交一个不需要返回值的任务给线程池执行。它接收一个 Runnable 类型的参数,并且不返回任何结果。

使用示例代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecuteDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 使用 execute 方法提交任务
        executor.execute(() -> {
            System.out.println("Task running in " + Thread.currentThread().getName());
            try {
                // 模拟任务执行
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.err.println("Task was interrupted");
            }
            System.out.println("Task finished");
        });

        // 关闭线程池
        executor.shutdown();
    }
}

说明execute 方法适用于那些只需要执行任务,而不需要关心任务执行结果的场景。


submit 方法

submit 方法用于提交一个需要返回值的任务(Callable 对象),或者不需要返回值但希望获取任务状态的任务(Runnable 对象)。它接收一个 CallableRunnable 类型的参数,并返回一个 Future 对象,通过该对象可以获取任务的执行结果或检查任务的状态。

2.1 提交 Callable 任务

示例代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SubmitCallableDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 提交一个 Callable 任务给线程池执行
        Future<String> future = executorService.submit(() -> {
            Thread.sleep(2000); // 模拟任务执行时间
            return "Task's execution result";
        });

        try {
            // 获取任务的执行结果
            String result = future.get();
            System.out.println("Task result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

说明submit 方法适用于需要获取任务执行结果的场景,通过 Future 对象可以方便地获取返回值。

2.2 提交 Runnable 任务

示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SubmitRunnableDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 提交一个 Runnable 任务给线程池执行,并获取一个 Future 对象
        Future<?> future = executorService.submit(() -> {
            System.out.println("Task is running in thread: " + Thread.currentThread().getName());
        });

        // 检查任务是否完成(这里只是为了示例,实际使用中可能不需要这样做)
        if (future.isDone()) {
            System.out.println("Task is done");
        } else {
            System.out.println("Task is not done yet");
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

说明:即使提交的是 Runnable 任务,submit 方法也会返回一个 Future 对象,可以用来检查任务的状态。


遇到未处理异常

线程池在遇到未处理异常时的行为与添加任务的方法有关,execute 方法和 submit 方法的行为是不同的。

3.1 execute 方法遇到未处理异常

示例代码:

import java.util.concurrent.*;

public class ThreadPoolExecutorExceptionTest {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(100)
        );

        // 添加任务一
        executor.execute(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("线程名:" + tName);
            throw new RuntimeException("抛出异常");
        });

        // 添加任务二
        executor.execute(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("线程名:" + tName);
            throw new RuntimeException("抛出异常");
        });
    }
}

执行结果

线程名:pool-1-thread-1
线程名:pool-1-thread-2

说明

  • 当使用 execute 方法时,如果任务抛出未捕获的异常,线程会崩溃并打印异常信息,但不会影响其他线程的运行。
  • 在上述代码中,两个任务分别在不同的线程中执行,即使任务抛出异常,线程池仍然可以正常运行。

3.2 submit 方法遇到未处理异常

示例代码:

import java.util.concurrent.*;

public class ThreadPoolExecutorExceptionTest {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                1,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(100)
        );

        // 添加任务一
        Future<?> future = executor.submit(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("线程名:" + tName);
            throw new RuntimeException("抛出异常");
        });

        // 添加任务二
        Future<?> future2 = executor.submit(() -> {
            String tName = Thread.currentThread().getName();
            System.out.println("线程名:" + tName);
            throw new RuntimeException("抛出异常");
        });

        try {
            future.get();
        } catch (Exception e) {
            System.out.println("遇到异常:" + e.getMessage());
        }

        try {
            future2.get();
        } catch (Exception e) {
            System.out.println("遇到异常:" + e.getMessage());
        }
    }
}

执行结果

线程名:pool-1-thread-1
遇到异常:java.lang.RuntimeException: 抛出异常
线程名:pool-1-thread-1
遇到异常:java.lang.RuntimeException: 抛出异常

说明

  • 当使用 submit 方法时,任务抛出的异常会被封装在 Futureget 方法中,而不会直接影响执行任务的线程。
  • 线程池中的线程可以继续复用,不会因为任务抛出异常而崩溃。

小结

线程池在遇到未处理的异常时,不同添加任务的方法的执行行为是不同的:

  • execute 方法:遇到未处理的异常,线程会崩溃,并打印异常信息。
  • submit 方法:遇到未处理的异常,线程本身不会受到影响(线程可以复用),只是将异常信息封装到返回的对象 Future 中。

理解这两种方法的区别,可以帮助我们在实际开发中更好地选择适合的线程池任务提交方式


http://www.kler.cn/a/512873.html

相关文章:

  • 逆波兰表达式求值(力扣150)
  • 气膜料仓:工业仓储的高效与安全新选择—轻空间
  • 【博客之星2024】技术创作与成长的全景回顾与突破 —— “千里之行,始于足下“
  • 工业网口相机:如何通过调整网口参数设置,优化图像传输和网络性能,达到最大帧率
  • Mac下安装ADB环境的三种方式
  • 跨境电商使用云手机用来做什么呢?
  • Redis的Windows版本安装以及可视化工具
  • PHP代码审计学习01
  • Github 2025-01-20 开源项目周报 Top15
  • Docker:基于自制openjdk8镜像 or 官方openjdk8镜像,制作tomcat镜像
  • Linux 时间操作详解
  • 什么是馈线自动化(FA)?其优点是什么?本文给出答案
  • 14,c++——继承
  • VSCode 使用默认profile打开文件
  • SpringBoot配置文件高级用法实战
  • RabbitMQ使用随笔
  • C语言勘破之路-最终篇 —— 预处理(上)
  • 高质量编程 性能优化学习笔记
  • redis-redission的加锁源码与看门狗机制
  • 【人工智能数学基础—微积分】深入详解梯度与梯度下降:掌握梯度下降法及其变种及模型参数的优化
  • 14天学习微服务-->第1天:微服务架构入门
  • Java锁 死锁及排查 JVM 工具 jconsole 工具 排查死锁
  • R语言的编程范式
  • cuda从零开始手搓PB神经网络
  • QT:多窗口设计(主窗口点击按钮打开子窗口)
  • 开源的Text-to-SQL工具WrenAI