java多线程——初识Executor框架

Executor框架概览

    如图所示,Executor接口作为框架的根定义了execut()方法,该方法负责执行提交的任务,ExecutorService接口在该接口的基础上增加了一些服务方法,AbstractExecutorService抽象类实现了一些通用方法,ScheduledExecutorService接口继承了ExecutorService接口并增加了一些定时执行任务的方法,ThreadPoolExecutor类扩展AbstractExecutorService类提供了丰富的使用方法,ScheduledThreadPoolExecutor类在实现ScheduledExecutorService接口扩展ThreadPoolExecutor类,提供了丰富的定时任务方法。


Executor1.png

ThreadPoolExecutor类定义的方法视图:


方法.png

  Executor框架解决了任务提交与任务执行的耦合问题,我们从一个简单的计算二维数组各行和,最终计算整个数组元素和的例子开始:


public class DemoMain {
    
    //定义需要计算的二维数组
    private static int [][] array= {{1,2,3},{4,5,6},{7,8,9}};
    
    /**
     * @param i
     * @return 获取各行和
     */
    private static int getRowSum(int i) {
        int result=0;
        for(int j=0;j

输出结果为:

线程Thread-0计算数组第0行的和为6
线程Thread-2计算数组第2行的和为24
线程Thread-1计算数组第1行的和为15

  在以上三行三列的数组计算中,我们计算每行数组和时都启用一个线程独立的运算,需要手动创建三个线程与计算任务Task绑定到一起,再调用star()方法执行任务,在这个过程中线程类与任务类的绑定,任务的执行都与Thread对象相耦合。下图是Thread类给我们提供的可以调用的方法,我将常用的标注了出来:

Thread类方法.png

使用Executor框架,修改main方法如下:

public static void main(String[] args) {
    //定义一个线程池对象,使用Executors工具类提供的无界队列构造线程池;
        ExecutorService executor=Executors.newCachedThreadPool();
        for(int i=0;i

利用执行器执行任务,已经为我们屏蔽了具体线程的创建,使得任务的提交与任务的执行解耦,执行器提供了丰富的任务执行控制方法:


ExecutorService.png

在改进中使用了Executors工具类的线程池 newCachedThreadPool(),该工具类中定义了以下几种线程池以供直接使用:


Executors框架定义的返回执行器的方法1.png
Executors框架定义的返回线程池的方法2.png

在java.util.concurrent包中定义了ThreadPoolExecutor类,可以根据该类的构造函数,设置不同参数,得到自定义的线程池类型:


ThreadPoolExecutor构造函数.png

线程池组合使用了阻塞队列,下图给出了阻塞队列的UML图:


阻塞队列.png

    阻塞队列与一般队列相比,增加了两种操作:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。所以阻塞队列拥有两套插入、移除的操作支持阻塞与非阻塞运用:


阻塞队列的操作.png

    在线程池中使用阻塞队列,主要是利用其阻塞操作,任务提交到线程池后在核心线程数不够用于执行所有任务时,会首先尝试再创建新的线程来执行任务,直到总的线程数超过线程池最大线程数,任务被缓存在阻塞队列中,如果有线程空闲了,就会从该队列中提取任务来执行;同时阻塞队列也是线程安全的,不会存在两个线程同时从阻塞队列中争抢同一个任务。

你可能感兴趣的:(java多线程——初识Executor框架)