java线程池——Executor框架详解

一、前言

定义
线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。

使用线程池的优势

  • 1、线程和任务分离,提升线程重用性;
  • 2、控制线程并发数量,降低服务器压力,统一管理所有线程;
  • 3、提升系统响应速度,假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;

为什么要是用线程池
可以根据系统的需求和硬件环境灵活的控制线程的数量,且可以对所有线程进行统一的管理和控制,从而提高系统的运行效率,降低系统运行运行压力

二、Executor框架

(一)什么是Executor框架?
我们知道线程池就是线程的集合,线程池集中管理线程,以实现线程的重用,降低资源消耗,提高响应速度等。线程用于执行异步任务,单个的线程既是工作单元也是执行机制,从JDK1.5开始,为了把工作单元与执行机制分离开,Executor框架诞生了,他是一个用于统一创建与运行的接口。Executor框架实现的就是线程池的功能。

Executor框架的成员

三、Executor框架结构

1、Executor框架包括3大部分:
(1)任务。也就是工作单元,包括被执行任务需要实现的接口:Runnable接口或者Callable接口;
(2)任务的执行。也就是把任务分派给多个线程的执行机制,包括Executor接口及继承自Executor接口的ExecutorService接口。
(3)异步计算的结果。包括Future接口及实现了Future接口的FutureTask类。

2、Executor框架的使用示意图

Runnable对象、Callable对象:
使用步骤:https://blog.csdn.net/fendouderen/article/details/126562398

四、创建线程池的方式

(一)通过 ThreadPoolExecutor 构造函数实现

定义MyRunnable类实现Runnable接口,并实现run方法

public class MyRunnable implements Runnable{  
    String name;  
    public MyRunnable(String name){  
        this.name = name;  
    }  
    @Override  
    public void run() {  
        System.out.println(Thread.currentThread().getName() + name + "上山");  
    }  
}

使用ThreadPoolExecutor创建线程池

public class RealPool {  
    //核心线程数  
    static int corePoolSize = 3;  
    //最大线程数  
    static int maximumPoolSize = 6;  
    //超过 corePoolSize 线程数量的线程最大空闲时间  
    static long keepAliveTime = 2;  
    //以秒为时间单位  
    static TimeUnit unit = TimeUnit.SECONDS;  
    //对应创建工作队列,用于存放提交的等待执行任务,此处填写队列大小  
    static int queueSize = 20000;  
  
    public static void main(String[] args) {  
        Long start = System.currentTimeMillis();  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
                corePoolSize,  
                maximumPoolSize,  
                keepAliveTime,  
                unit,  
                new ArrayBlockingQueue<>(queueSize),  
                new ThreadPoolExecutor.AbortPolicy()  
        );  
  
        MyRunnable r1 = new MyRunnable("realPool");  
        MyRunnable r2 = new MyRunnable("狗狗");  
        MyRunnable r3 = new MyRunnable("猫猫");  
        executor.execute(r1);  
        executor.execute(r2);  
        executor.execute(r3);  
        executor.shutdown();  
        Long end = System.currentTimeMillis();  
        System.out.println("花费时间为:"+ (end-start) + "ms");  
  
    }  
}
execute与submit

提交任务的类型:

  • execute和submit都属于线程池的方法,execute只能提交Runnable类型的任务
  • submit既能提交Runnable类型任务也能提交Callable类型任务。
    异常:
  • execute会直接抛出任务执行时的异常,可以用try、catch来捕获,和普通线程的处理方式完全一致
  • submit会吃掉异常,可通过Future的get方法将任务执行时的异常重新抛出。
    返回值:
  • execute()没有返回值
  • submit有返回值,所以需要返回值的时候必须使用submit
public void execute(Runnable command) {  
	// 如果实现类是null,则报NullPointerException错误
    if (command == null)  
        throw new NullPointerException();  
     //   主池控制状态ctl是一个原子整数,包装了两个概念字段workerCount,表示有效线程数runState,表示是否正在运行、正在关闭等为了将它们打包成一个int
     // 获取线程的状态
        int c = ctl.get();  
     // 如果当前工作线程少于核心线程,则加一个线程,并把实现类放进去
    if (workerCountOf(c) < corePoolSize) {  
        if (addWorker(command, true))  
            return;  
        c = ctl.get();  
    }  
	 // 如果当前执行的任务数量大于等于 corePoolSize 的时候就会走到这里
	 // 如果线程池正执行,且队列能放新元素,则执行内部
    if (isRunning(c) && workQueue.offer(command)) {  
        int recheck = ctl.get();  
        再次获取线程池状态,如果线程池状态不是 RUNNING 状态就需要从任务队列中移除任务,并尝试判断线程是否全部执行完毕。同时执行拒绝策略。
        if (! isRunning(recheck) && remove(command))  
            reject(command);  
            // 如果当前线程池为空就新创建一个线程并执行。
        else if (workerCountOf(recheck) == 0)  
            addWorker(null, false);  
    }  
    // 创建线程后执行失败,则执行拒绝策略
    else if (!addWorker(command, false))  
        reject(command);  
}

(二)通过工厂类 Executors 来实现

不建议使用
在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。
而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险
具体实现
https://blog.csdn.net/fendouderen/article/details/126562398

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我来给您讲解一下Java中的Executor框架。 在Java中,Executor框架是一种用于管理线程的高级工具。该框架允许开发者使用高级的API来管理线程,而无需直接使用底层线程管理机制。 Executor框架中的主要接口是ExecutorExecutorService。Executor接口定义了一个用于执行任务的方法,而ExecutorService则是一个扩展了Executor接口的接口,它提供了一系列管理任务和线程的方法,如提交任务、关闭线程池等。 在Executor框架中,任务被封装为实现了Runnable接口或Callable接口的对象。其中,Runnable接口表示一个没有返回值的任务,而Callable接口则表示一个可以返回结果的任务。这些任务被提交给线程池执行,线程池中的线程会从任务队列中获取任务并执行。 Executor框架提供了多种不同类型的线程池,如FixedThreadPool、CachedThreadPool、SingleThreadPool等。其中,FixedThreadPool是一个固定大小的线程池,CachedThreadPool是一个可以自动扩容的线程池,而SingleThreadPool则是一个只有一个线程的线程池。 除了线程池之外,Executor框架还提供了一些其他的工具类,如ScheduledExecutorService用于定时执行任务、CompletionService用于管理异步任务等。 总的来说,Executor框架是一个非常实用的线程管理工具,它简化了线程管理的复杂性,并提供了多种线程池和工具类,帮助开发者更加方便地管理线程。 ### 回答2: Executor框架Java提供的一个用于管理和调度线程的高级框架。它在java.util.concurrent包下,提供了一组接口和类来处理线程的创建、启动、执行和调度。 Executor框架主要包含了三个核心组件:ExecutorExecutorService和ThreadPoolExecutor。 首先,Executor是一个接口,它定义了一个简单的方法execute(Runnable command),用于执行传入的任务。它隐藏了线程的创建和启动过程,只需要将任务交给Executor,它会在后台自动创建线程并执行任务。 其次,ExecutorService是一个接口,它继承自Executor接口,并增加了一些管理和控制线程的方法。它提供了submit(Callable task)方法,用于提交有返回值的任务,并返回一个Future对象,可以通过该对象获取任务的执行结果。ExecutorService还提供了shutdown()和shutdownNow()方法,用于优雅地停止线程池的运行。 最后,ThreadPoolExecutorExecutorService接口的一个实现类。它实现了一个基于线程池ExecutorService,可以根据任务的数量和需要的资源动态地创建、回收和管理线程。ThreadPoolExecutor通过内部的任务队列和线程池来实现任务的调度和执行。可以通过调整线程池的参数来控制并发执行的线程数量和线程的优先级。 Executor框架的使用可以提供多线程编程的简化和优化。它可以将任务的提交和执行进行分离,将任务的执行交给线程池管理,从而充分复用线程资源,避免线程创建和销毁的开销。同时,它还提供了任务的调度和控制功能,可以根据需要在多个线程之间进行任务的切换和调度,提高系统的运行效率和资源利用率。 总结来说,在Java中,Executor框架是一个强大的并发编程工具,通过它我们可以方便地管理和控制线程的执行,提高程序的性能和响应速度。 ### 回答3: Executor框架Java中用于管理和调度线程的一个重要框架。它提供了一种简单且高效的方式来执行异步任务,并且能够更好地管理线程池资源。 Executor框架提供了一个Executor接口,该接口定义了一个线程池的基本执行操作。常见的实现类有ThreadPoolExecutor和ScheduledThreadPoolExecutor,它们都是Executor接口的具体实现。 通过Executor框架,我们可以使用线程池执行任务,从而避免了为每个任务创建新线程带来的开销。我们只需要将任务提交给线程池即可,线程池会自动进行线程的创建和管理,实现任务的异步执行。 Executor框架还提供了一些功能丰富的方法,如submit()方法和invokeAll()方法。submit()方法用于提交一个任务并返回一个表示该任务结果的Future对象,我们可以利用Future对象来获取任务的执行结果或取消任务的执行。invokeAll()方法用于同时提交多个任务,并等待所有任务完成。 除了常规的线程池功能外,Executor框架还引入了一些用于定时任务调度的类,例如ScheduledThreadPoolExecutor和ScheduledExecutorService。这些类可以实现任务的定时执行、周期执行以及延迟执行等功能。 总之,Executor框架Java中管理和调度线程的重要工具。它提供了一种高效的线程池资源管理方式,并且提供了一些方便的方法来操作和管理任务的执行。在实际开发中,合理地使用Executor框架可以提高程序的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值