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<array.length;j++) {
            result+=array[i][j];
        }
        return result;
    }
    /**
     * @author 54353
     * 线程任务类
     */
    public static class Task implements Runnable{
        //定义计算行
        private int row;
        public Task(int row) {
            this.row=row;
        }
        @Override
        public void run() {
            int sum=getRowSum(row);
            System.out.println("线程"+Thread.currentThread().getName()+"计算数组第"+row+"行的和为"+sum);
        }
    }
    public static void main(String[] args) {
        Task task0=new Task(0);
        Task task1=new Task(1);
        Task task2=new Task(2);
        new Thread(task0).start();
        new Thread(task1).start();
        new Thread(task2).start();
    }
}

输出结果为:

线程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<array.length;i++) {
            executor.execute(new Task(i));
        }
}

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


ExecutorService.png

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


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

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


ThreadPoolExecutor构造函数.png

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


阻塞队列.png

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


阻塞队列的操作.png

    在线程池中使用阻塞队列,主要是利用其阻塞操作,任务提交到线程池后在核心线程数不够用于执行所有任务时,会首先尝试再创建新的线程来执行任务,直到总的线程数超过线程池最大线程数,任务被缓存在阻塞队列中,如果有线程空闲了,就会从该队列中提取任务来执行;同时阻塞队列也是线程安全的,不会存在两个线程同时从阻塞队列中争抢同一个任务。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 【JAVA 线程】 线程 进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者...
    Rtia阅读 2,800评论 2 20
  • 线程池的概念和定义 在服务器端的业务应用开发中,Web服务器(诸如Tomcat、Jetty)需要接受并处理http...
    dtdh阅读 856评论 0 1
  • 第一部分 来看一下线程池的框架图,如下: 1、Executor任务提交接口与Executors工具类 Execut...
    压抑的内心阅读 4,315评论 1 24
  • 爱我们所爱,但要知道我们所爱的都如朝露。——塞雷卡 我们拥有的一切都是从幸运女神那里暂借而来,它随时会把它收走。
    雷电2002阅读 290评论 0 0
  • #幸福是需要修出来的~每天进步1%~幸福实修14班~01组李玉珍# 20180123(1/60) 【幸福实修目标】...
    stx2010阅读 158评论 2 1