Java多线程工具包java.util.concurrent---ExecutorService

2023-11-11

什么是ExecutorService

java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务。因此一个 ExecutorService 很类似于一个线程池。实际上,存在于 java.util.concurrent 包里的 ExecutorService 实现就是一个线程池实现。

ExecutorService的实现

ExecutorService 接口的以下实现类:

  • ThreadPoolExecutor
  • ScheduledThreadPoolExecutor

工厂java.util.concurrent.Executors 类

Executors提供了多个工厂方法,下面来具体说明
首先看下ThreadPoolExecutor

int  corePoolSize  =    5;  
int  maxPoolSize   =   10;  
long keepAliveTime = 5000;  

ExecutorService threadPoolExecutor =  
        new ThreadPoolExecutor(  
                corePoolSize,  
                maxPoolSize,  
                keepAliveTime,  
                TimeUnit.MILLISECONDS,  
                new LinkedBlockingQueue<Runnable>()  
                );  

以下是jdk1.6中文API对参数解释

corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序创建新线程时使用的工厂。

这里说明一下corePoolSize
核心线程会一直存活,即使没有任务需要执行

  • newSingleThreadExecutor()

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

由参数可知,创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务
示例

package com.yvacn.executorServiceCallable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * 
 * @author yvan
 *
 */
public class AppMainTestSingle {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "执行" + this.toString());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + "执行" + this.toString());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.shutdown();
    }
}

结果

pool-1-thread-1执行com.yvacn.executorServiceCallable.AppMainTestSingle$1@6695b54d
pool-1-thread-1执行com.yvacn.executorServiceCallable.AppMainTestSingle$2@685257ef

由结果也可以看出,线程池中有一个线程且是顺序执行(FIFO)

  • newFixedThreadPool

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

示例

package com.yvacn.executorServiceCallable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * 
 * @author yvan
 *
 */
public class AppMainTestFixedPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                    System.out.println("我是线程一");
                    System.out.println(Thread.currentThread().getName() + "执行" );
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(200);
                    System.out.println("我是线程二");
                    System.out.println(Thread.currentThread().getName() + "执行" );
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                    System.out.println("我是线程三");
                    System.out.println(Thread.currentThread().getName() + "执行");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.shutdown();
    }
}

结果

我是线程二
pool-1-thread-2执行
我是线程三
pool-1-thread-2执行
我是线程一
pool-1-thread-1执行

由结果可以看出,虽然提交三个执行任务,但是因为固定的线程池为2,只创建了2个线程在执行任务
-

newCachedThreadPool


创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

示例

package com.yvacn.executorServiceCallable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * 
 * @author yvan
 *
 */
public class AppMainTestFixedPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                    System.out.println("我是线程一");
                    System.out.println(Thread.currentThread().getName() + "执行" );
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(200);
                    System.out.println("我是线程二");
                    System.out.println(Thread.currentThread().getName() + "执行" );
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                    System.out.println("我是线程三");
                    System.out.println(Thread.currentThread().getName() + "执行");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        executorService.shutdown();
    }
}

结果

我是线程三
pool-1-thread-3执行
我是线程二
pool-1-thread-2执行
我是线程一
pool-1-thread-1执行

  • newScheduledThreadPool


    创建一个定长线程池,支持定时及周期性任务执行
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

示例

package com.yvan.scheduledExecutorService;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
 * 
 * @author yvan
 *
 */
public class AppMain {

    private static int count = 0;


    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws Exception {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                count++;
                System.out.println(format.format(new Date()) + "---执行" + count + "次");
            }
        }, // 执行线程
                1000, // 初次延迟多久执行
                5000, // 执行间隔时间
                TimeUnit.MILLISECONDS // 执行间隔时间类型,此处为毫秒
        );
        ScheduledFuture<Object> reuslt = executorService.schedule(new Callable<Object>() {

            @Override
            public Object call() throws Exception {
                return count;
            }

        }, 7000, TimeUnit.MILLISECONDS);
        System.out.println(reuslt.get().toString());
        executorService.shutdown();
    }
}

结果

2017-11-23 15:33:28—执行1次
2017-11-23 15:33:33—执行2次
2

execute和submit

下面的示例中说明了他们的不同以及用法

package com.yvacn.executorServiceCallable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
 * 
 * @author yvan
 *
 */
public class AppMain {
    public static void main(String[] args) throws Exception {
        ExecutorService eService = Executors.newCachedThreadPool();
        //execute Runnable
        eService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+"开始执行");
                    TimeUnit.MILLISECONDS.sleep(1000);
                    System.out.println(Thread.currentThread().getName()+"   执行完毕");;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        //submit Callable
        //call函数返回的结果放入Future中
        Future<Object> future = eService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                System.out.println(Thread.currentThread().getName()+"开始执行");
                TimeUnit.MILLISECONDS.sleep(1000);
                return Thread.currentThread().getName()+"   执行完毕";
            }
        });
        // submit Runnable
        //如果返回的结果为null说明线程执行完毕
        Future<?> future1 = eService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+"开始执行");
                    TimeUnit.MILLISECONDS.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println(future.get().toString());
        while (future1.get()==null) {
            System.out.println( "submit Runnable 执行完毕");
            break;
        }
        eService.shutdown();

    }
}

如何终止线程

  • shutdown()

ExecutorService
并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭。在
shutdown() 被调用之前所有提交给 ExecutorService 的任务都被执行。

  • shutdownNow()

如果你想要立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这样会立即尝试停止所有执行中的任务,并忽略掉那些已提交但尚未开始处理的任务。无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程工具包java.util.concurrent---ExecutorService 的相关文章

随机推荐

  • [JDBC连接] 使用JDBC操作数据库中的数据

    目录 什么是JDBC 前期配置 连接数据库 JDBC操作数据库 基本操作执行静态SQL语句 预编译操作执行动态SQL语句 处理返回结果 查询结果 增删改结果 JDBC处理事务 Druid连接池 关闭资源 总结 什么是JDBC JDBC就是通
  • 1-3年 Android 开发工程师面试经验分享

    code小生 一个专注 Android 领域的技术平台 公众号回复 Android 加入我的安卓技术群 作者 Android大强哥链接 https www jianshu com p 812a92661e82声明 本文已获Android大强
  • redis自增,定时任务更新评论数和阅读数

    redis定时任务自增实现阅读数和评论数更新 阅读数和评论数 考虑把阅读数和评论数 增加的时候 放入redis incr自增 使用定时任务 定时把数据固话到数据库当中 点击文章的方法里面实现文章阅读数自增 public ArticleVo
  • PAT 1018 锤子剪刀布 (20分)

    1018 锤子剪刀布 20分 大家应该都会玩 锤子剪刀布 的游戏 两人同时给出手势 胜负规则如图所示 现给出两人的交锋记录 请统计双方的胜 平 负次数 并且给出双方分别出什么手势的胜算最大 输入格式 输入第 1 行给出正整数 N 10 5
  • linux内核I2C子系统学习(一)

    这部分准备分几个部分进行分析总结 因为I2C的通信肯定至少要有2个芯片完成 所以它的驱动是由2大部分组成 主芯片的i2c的驱动 从芯片的i2c的驱动 注 万一选的都不支持咋办 惨了 只能2个芯片的驱动都得实现了 不过过程差不多 一 主芯片的
  • selenium使用send_keys方式上传附件

    在运用selenium进行自动化测试的过程中 可能会遇到执行上传附件的操作 如果是input类型的标签 并且type值为 file 那么可以直接通过send keys的方法来绕过弹出框操作 直接将文件信息传递给 添加附件 按钮 示例 使用s
  • 2022-2027年中国中医药行业发展监测及投资战略研究报告

    报告类型 产业研究 报告格式 电子 纸介版 出品单位 华经产业研究院 本报告由华经产业研究院重磅推出 对中国中医药行业的发展现状 竞争格局及市场供需形势进行了具体分析 并从行业的政策环境 经济环境 社会环境及技术环境等方面分析行业面临的机遇
  • Cesium入门理解与学习路线

    Cesium入门理解与学习路线 1 Cesium入门 CesiumJS是一个开放源代码JavaScript库 用于创建具有最佳性能 精度 视觉质量和易用性的世界一流的3D地球和地图 从航空航天到智慧城市再到无人机 各行各业的开发人员都使用C
  • php 引入 七牛sdk,thinkphp3.2.3 引入七牛SDK

    第一种方式 Composer安装 1 安装Composer 2 命令行输入 php composer phar require qiniu php sdk composer用法参考composer官方文档 3 在入口文件index php引
  • Navicat-MySQL报错1449 - The user specified as a definer (‘mysqlinfoschema‘@‘localhost‘) does not exist

    问题 Ubuntu20 04虚拟机部署了MySQL8 0 32 本机Navicat连接MySQL 测试连接成功 但是确定后连接报错 1449 The user specified as a definer mysqlinfoschema l
  • sql优化原则【摘】

    sql优化原则 下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍 在这些where子句中 即使某些列存在索引 但是由于编写了劣质的SQL 系统在运行该SQL语句时也不能使用该索引 而同样使用全表扫描 这就造成了响应速度的极
  • react数组循环渲染

    正常来说我们的页面很多数据都是动态渲染的 我们一般根据一个数组来进行动态渲染 在react里面没有类似vue的指令 所以我们必须自己手动循环生成 在react里面我们一般采用map方法对数组进行循环 因为map方法可以返回我们想要渲染的js
  • JAVA面向对象--继承性

    一 继承性 继承是面向对象的第二大特性 而继承性要解决的就是代码重用问题 利用继承性可以从已有的类继续派生处新的子类 也可以利用子类扩展处更多的操作功能 继承性严格来讲就是指扩充一个类已有的功能 如法如下 class 子类 extends
  • 华为企业管理经典案例_干货丨华为项目管理案例PPT(54P)

    向成功的标杆企业学习 向从实践中总结的管理精髓学习 永远是我们最明智的选择 华为一直非常重视项目管理 项目管理在促进公司发展 实现商业价值 推动人才培养等方面发挥了重要作用 华为的项目管理是一种业务运作模式 华为 以项目为中心 的运作不仅仅
  • Database Collection

    RetargetMe https people csail mit edu mrub retargetme Image Retargeting Subjective Quality Databse http ivp ee cuhk edu
  • python错误 module 'urllib' has no attribute 'request'

    因为python3 X有时候不会将子模块自动导入进去 所以改成import url request问题就解决了
  • 使用vue+element ui实现el-tabs文字不动 鼠标经过背景淡入淡出的动画效果以及改element ui tabs 修改成hover触发点击

    el tabs的结构
  • proxy_set_header导致跨域失败分析

    跨域失败分析 proxy set header Host host 这个配置导致跨域失败 配置的作用是把原http请求的header中的host字段 即域名 放到转发请求里面 解决方案 配置成 proxy set header Host t
  • 【STM32技巧】STM32 CubeMX中定时器四种从机模式说明

    四种从机模式说明 外部时钟模式1从模式 External Clock Mod1 这个模式比较特别 名字也有点奇葩 其实 这个从模式跟时钟源的外部时钟模式1有渊源 在介绍计数器时钟源时 讲到过外部时钟模式1 即计数器的时钟来自TI1或TI2的
  • Java多线程工具包java.util.concurrent---ExecutorService

    什么是ExecutorService java util concurrent ExecutorService 接口表示一个异步执行机制 使我们能够在后台执行任务 因此一个 ExecutorService 很类似于一个线程池 实际上 存在于