Java高并发编程中Executor、ExecutorService的使用及详细介绍-刘宇

本文详细介绍了Java高并发编程中Executor框架的使用及原理,包括Executor、ExecutorService接口的解析,线程池的创建与管理,以及关键方法如submit、invokeAny、invokeAll的运用。同时,通过示例演示了如何捕获线程执行过程中的异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:刘宇
CSDN博客地址:https://blog.csdn.net/liuyu973971883
有部分资料参考,如有侵权,请联系删除。如有不正确的地方,烦请指正,谢谢。

一、什么是Executor框架

Executor是从Java5中才开始有的,在java.util.cocurrent包下,是非常强大的异步执行框架,标准的将任务提交过程和执行过程进行解耦。内部使用了线程池机制,可以通过该框架来控制线程的启动、执行、关闭等,大大提高了并发开发的效率。

二、Executor框架示意图

在这里插入图片描述

  • Executor:是一个基本接口,提供方法execute(Runnable command),该方法接收一个Runable实例,将提交任务的过程与执行任务的过程进行了解耦。
  • ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
  • AbstractExecutorService:ExecutorService执行方法的默认实现
  • ScheduledExecutorService:一个可定时调度任务的接口
  • ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
  • ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池

三、ExecutorService的方法详解

1、submit方法

//提交一个Runnable的任务,该任务没有返回结果,虽然返回一个Future对象,但是Future的get是null。
Future<?> submit(Runnable task)
//提交一个Runnable的任务,该任务可以有返回值,通过传入的result对象返回结果。
<T> Future<T> submit(Runnable task, T result)
//提交一个Callable的任务,该任务可以有返回值,因为Callable与Runnable不同,Callable自身就可以返回结果
<T> Future<T> submit(Callable<T> task)

2、invokeAny方法

该方法会阻塞。批量提交任务并执行所有callable,直到获得一个已经成功执行的任务的结果,如果一个任务已经完成,剩余的Callable任务将被取消即使它在运行也会被取消。

  • tasks:Callable类型的集合
  • timeout:超时时间
  • unit:时间单位

异常处理:

  • 如果Callable集合中只有部分Callable异常,则即使是将该异常抛出,在其调用的地方也是无法捕获异常的,因为该Callable异常了,则会调用Callable集合中的下一个Callable。
  • 如果Callable集合中的Callable全部异常,则可以在其调用的地方捕获异常的。
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

3、invokeAll方法

该方法会阻塞。批量提交任务并获得他们的future,Task列表与Future列表一一对应

  • tasks:Callable类型的集合
  • timeout:超时时间
  • unit:时间单位

异常处理

  • 当线程池中线程发送发生异常时,直接在抛出,可以在其调用的方法捕获异常,但是只有在调用Future中的get才能捕获异常,否则则一样捕获不到。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;

4、awaitTermination方法

是阻塞方法。等待一定时间后如果有任务未结束则强行关闭

boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

5、isShutdown方法

判断该Executor是否关闭,调用shutdown后会变为true,即使Executor还没有关闭。

boolean isShutdown();

6、shutdown方法

是非阻塞方法。不再接受新的任务,等待所有任务执行完毕后关闭Excutor

void shutdown();

7、shutdownNow方法

  • 它会对正在执行的线程进行interrupt,也有可能存在interrupt不成功的现象,如该线程中没有sleep、wait、join等即没有抛出中断异常的方法,则可能会出现中断失败
  • 将空闲线程取消
  • 会返回未执行的任务列表
List<Runnable> shutdownNow()

8、isTerminated方法

是非阻塞方法。判断是否Executor是否已终结,调用shutdown后该方法并不会立即返回true,只有等到所有任务都结束,Executor真正结束时才返回true

boolean isTerminated()

四、ExecutorService练习

Executors工具类这里只要理解为快建创建线程池的工具类就可以了,Executors的使用详情请看后面的博客

1、如何捕获线程执行过程中出现的异常并处理

1.1 利用Thread中uncaughtExceptionHandler来处理

  • 弊端:捕获异常时无法得知实体任务中的属性。
package com.test.part3.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class ExecutorServiceExample {

    public static void main(String[] args) {
    	//创建一个core和最大线程数都为5,空闲时间为0的线程池,并且指定一个我们自己的ThreadFactory
        ExecutorService executorService = Executors.newFixedThreadPool(5,new ThreadFactory());
        IntStream.rangeClosed(1,5).boxed().forEach(i->{
            executorService.execute(()->{
                System.out.println(1/0);
            });
        });
    }
    private static class ThreadFactory implements java.util.concurrent.ThreadFactory {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            //对线程中的异常进行捕获,但这种情况并不能得知线程任务中的属性
            t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println(t.getName()+": 发生了异常");
                    e.printStackTrace();
                }
            });
            return t;
        }
    }
}

运行结果

Thread-0: 发生了异常
Thread-2: 发生了异常
Thread-1: 发生了异常
Thread-3: 发生了异常
Thread-4: 发生了异常
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample.lambda$null$0(ExecutorServiceExample.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample.lambda$null$0(ExecutorServiceExample.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample.lambda$null$0(ExecutorServiceExample.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample.lambda$null$0(ExecutorServiceExample.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample.lambda$null$0(ExecutorServiceExample.java:15)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

1.2 定义一个抽象的实现了Runnable接口的类来处理

package com.test.part3.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class ExecutorServiceExample {

    public static void main(String[] args) {
    	//创建一个core和最大线程数都为5的线程池,且该线程池的空闲时间为0
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        IntStream.rangeClosed(1,5).boxed().forEach(i->{
            executorService.execute(new MyTask(i) {
                @Override
                protected void doError(Throwable cause) {
                    System.out.println(Thread.currentThread().getName()+": 发生了异常, 编号: "+super.no);
                    cause.printStackTrace();
                }
            });
        });
    }
    private abstract static class MyTask implements Runnable{
        private int no;

        public MyTask(int no) {
            this.no = no;
        }

        @Override
        public void run() {
            try {
                //模拟做事情
                TimeUnit.SECONDS.sleep(1);
                System.out.println("编号:"+no+" 准备开始工作");
                //模拟做到一半时部分出现了异常
                if(no%3==0){
                    int num = 1/0;
                }
                System.out.println("编号:"+no+" 完成工作");
            } catch (Exception e) {
                doError(e);
            }
        }
        //交由外部实现
        protected abstract void doError(Throwable cause);
    }
}

输出结果:

编号:2 准备开始工作
编号:1 准备开始工作
编号:3 准备开始工作
编号:1 完成工作
编号:2 完成工作
pool-1-thread-3: 发生了异常, 编号: 3
编号:4 准备开始工作
编号:4 完成工作
编号:5 准备开始工作
编号:5 完成工作
java.lang.ArithmeticException: / by zero
	at com.test.part3.threadpool.ExecutorServiceExample$MyTask.run(ExecutorServiceExample.java:44)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
ExecutorServiceJava中的一个接口,它是Executor的子类接口,提供了一些额外的方法来管理任务的生命周期和获取异步任务的执行结果。ExecutorService,我们可以更方便地线程池来执行任务。 ExecutorService的一些常用方法包括: 1. submit方法:用于提交一个Runnable或Callable的任务,并返回一个Future对象。对于Runnable任务,Future的get方法将返回null;对于Callable任务,Future的get方法将返回任务的执行结果。 2. invokeAny方法:用于提交一组Callable任务,并返回其中一个任务的执行结果。它会阻塞直到有一个任务完成并返回结果,忽略其他任务的执行结果。 3. invokeAll方法:用于提交一组Callable任务,并返回所有任务的执行结果。它会阻塞直到所有任务都完成并返回结果。 4. awaitTermination方法:用于等待所有任务在指定的时间内完成。如果所有任务在超时时间内完成,则返回true;否则返回false。 5. isShutdown方法:用于判断ExecutorService是否已经关闭。 6. shutdown方法:用于平滑地关闭ExecutorService。它将停止接收新的任务,并等待已经提交的任务完成。 7. shutdownNow方法:用于立即关闭ExecutorService。它将尝试取消所有正在执行的任务,并返回等待执行的任务列表。 8. isTerminated方法:用于判断所有任务是否已经完成。 这些方法可以帮助我们更灵活地管理和控制线程池中的任务的执行。比如,通过submit方法可以提交任务并获取任务的执行结果;通过invokeAny方法可以获取一组任务中最先完成的任务的执行结果;通过shutdown方法可以平滑地关闭线程池等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java高并发编程ExecutorExecutorService使用详细介绍-刘宇](https://blog.csdn.net/liuyu973971883/article/details/107947496)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [java ExecutorService使用方法详解](https://download.csdn.net/download/weixin_38689477/12790401)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值