Java多线程之ExecutorService使用说明

一、简介

ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法。

二、线程池

Java给我们提供了一个 Executors工厂类,它可以帮助我们很方便的创建各种类型ExecutorService线程池,Executors一共可以创建下面这四类线程池:

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

三、代码举例

import org.junit.Test;
import java.util.concurrent.*;

/**
 * @author :gongxr
 * @description:ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法。 Java通过Executors提供四种创建线程池的工厂类,分别为:
 * newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
 * newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
 * newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
 * newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
 */

public class TestExecutorService {
    /**
     * newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
     */
    @Test
    public void test1() throws InterruptedException {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " 开始工作!");
                    Thread.sleep((long) (Math.random() * 3000));
                    System.out.println(Thread.currentThread().getName() + " 工作结束!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 5; i++) {
            cachedThreadPool.execute(runnable);
        }
        Thread.sleep(3000);
        System.out.println("主线程结束!");
        cachedThreadPool.shutdown();
    }

    /**
     * newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
     */
    @Test
    public void test2() throws InterruptedException {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " 开始工作!");
                    Thread.sleep((long) (Math.random() * 3000));
                    System.out.println(Thread.currentThread().getName() + " 工作结束!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 6; i++) {
            final int index = i;
            fixedThreadPool.execute(runnable);
        }
        Thread.sleep(6000);
        fixedThreadPool.shutdown();
        System.out.println("主线程结束!");
    }

    /**
     * newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
     * 该例中延迟3秒执行。
     */
    @Test
    public void test3_1() throws InterruptedException {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("delay 3 seconds");
            }
        };
        scheduledThreadPool.schedule(runnable, 3, TimeUnit.SECONDS);
        Thread.sleep(10000);
        scheduledThreadPool.shutdown();
    }

    /**
     * newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
     * 延迟1秒后每3秒执行一次。
     */
    @Test
    public void test3_2() throws InterruptedException {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("delay 1 seconds, and excute every 3 seconds");
            }
        };
        scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 3, TimeUnit.SECONDS);
        Thread.sleep(10000);
        scheduledThreadPool.shutdown();
    }

    /**
     * newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
     */
    @Test
    public void test4() throws InterruptedException {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            final int index = i;
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(index);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        Thread.sleep(10000);
        singleThreadExecutor.shutdown();
    }

    /**
     * submit(Callable)
     * submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,
     * 但是除此之外,submit(Callable)接收的是一个Callable的实现,
     * Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,
     * 而Runnable接口中的run()方法是void的,没有返回值。
     */
    @Test
    public void testCallable() throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Callable callable = new Callable() {
            @Override
            public Object call() throws InterruptedException {
                String name = Thread.currentThread().getName();
                System.out.println("Thread Name:" + name + " 开始工作!");
                Thread.sleep((long) (Math.random() * 3000));
                System.out.println("Thread Name:" + name + " 结束工作!");
                return name;
            }
        };

        Future future = executorService.submit(callable);

        System.out.println("主线程继续执行!");
        Thread.sleep(3000);

        // future.get()使得主线程阻塞,等待子线程执行结束
        System.out.println("子线程执行完回调结果:" + future.get().toString());

        System.out.println("主线程结束!");
        executorService.shutdown();
    }

    /**
     * ExecutorService的shutdown、shutdownNow、awaitTermination用法:
     * 调用shutdown方法之后,ExecutorService不再接收新的任务,直到当前所有线程执行完成才会关闭,所有之前提交的任务都会被执行。
     * 调用shutdownNow方法后,将试图阻止所有正在执行的任务和被提交还没有执行的任务。
     * awaitTermination方法的作用:监视各任务的状态是否已经结束,经过指定的时间后,全部完成返回true,反之返回false。
     */
    @Test
    public void testShutDown() throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " 开始工作!");
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + " 工作结束!");
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName() + " 子线程中断!");
                    e.printStackTrace();
                }
            }
        };
        // 线程1
        executorService.execute(runnable);
        Thread.sleep(1000);
        // 线程2
        executorService.execute(runnable);
        executorService.shutdown();
        // 等待一秒后检查子线程运行状态,全部完成返回true
        if (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
            System.out.println("主线程强制中断子线程!");
            executorService.shutdownNow();
        }
        Thread.sleep(4000);
        System.out.println("主线程结束!");
    }

}

与多线程同步工具结合使用:

运行结果:

Original: https://www.cnblogs.com/gongxr/p/14463568.html
Author: 星瑞
Title: Java多线程之ExecutorService使用说明

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/538054/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 字典服务的设计与管理

    编码问题,谁不想避其锋芒; 一、业务背景 在搜索引擎的功能上,曾经遇到过这样一个问题,数据库中某个公司名称中存在特殊编码,尽管数据已经正常同步到索引中,但是系统中关键词始终也无法匹…

    Java 2023年6月15日
    069
  • java反射与注解

    我们都知道,计算机运行代码,需要经过编译-运行这两个步骤,而反射就是当程序运行状态时,通过类名,就知道这个类有什么属性,有什么方法在里面.简而言之,在 Java 中,只要给定类的名…

    Java 2023年6月8日
    044
  • day44-反射03

    Java反射03 3.通过反射获取类的结构信息 3.1java.lang.Class类 getName:获取全类名 getSimpleName:获取简单类名 getFields:获…

    Java 2023年6月15日
    054
  • 程序设计基础·Java学习笔记·面向对象(下)

    Java程序设计基础之面向对象(下) (补充了上的一些遗漏的知识,同时加入了自己的笔记的ヾ(•ω•`)o) (至于为什么分P,啊大概是为了自己查笔记方便(?)应该是(〃` 3′〃)…

    Java 2023年6月7日
    084
  • Mysql基础篇-查询、函数、多表、事务

    基础篇 1.1 mysql用户和权限管理 查询用户 USER mysql; SELECT * FROM user; 创建用户 CREATE USER ‘&#x7528;&a…

    Java 2023年6月8日
    074
  • The One

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/stupidxixi/p/9444380.htmlAut…

    Java 2023年6月5日
    078
  • Idea的Debug

    来自CSDN:https://blog.csdn.net/yxl_1207/article/details/80973622 Original: https://www.cnblo…

    Java 2023年6月8日
    058
  • 【JavaWeb-JSP】笔记汇总 — JSP 规范;EL 表达式

    JSP 规范: <strong><span>JSP &#x89C4;&#x8303;&#x4ECB;&#x7ECD;&amp…

    Java 2023年6月8日
    069
  • Condition

    Profile是个好东西。通过Profile,我们可以非常方便地条件化Bean的创建,动态调整应用程序的功能。可是,Profile只能做些简单的条件化,对于复杂一点的条件化Prof…

    Java 2023年6月5日
    076
  • Java的虚拟线程(协程)特性开启预览阶段,多线程开发的难度将大大降低

    高并发、多线程一直是 Java编程中的难点,也是面试题中的要点。 Java开发者也一直在尝试使用多线程来解决应用服务器的并发问题。但是多线程并不容易,为此一个新的技术出现了,这就是…

    Java 2023年5月29日
    071
  • Kafka

    1. Kafka简介 1.1 消息队列 1.1.1 消息队列简介 消息Message:通讯设备之间传递的数据 队列Queue:一种特殊的线性表(数据元素首尾相连),特殊之处在于只允…

    Java 2023年6月8日
    088
  • Spring-Cloud-Ribbon学习笔记(一):入门

    Spring Cloud Ribbon是一个基于Http和TCP的客户端负载均衡工具,它是基于Netflix Ribbon实现的。它不像服务注册中心、配置中心、API网关那样独立部…

    Java 2023年5月30日
    052
  • PTA第6、7、8次作业的总结

    前言 这三次pta作业主要考查了电信计费系列的问题,从一开始的座机计费,再到座机计费与手机计费结合,最后到短信计费。其中座机计费与手机计费是难度最大的一次题目,因为它综合考虑的因素…

    Java 2023年6月5日
    059
  • Lambda表达式工具类-日常搬砖

    众所周知,jdk8提供的Lambda表达式能帮我极大的精简代码,但是就在我们在实际使用过程中会有一些重复性的代码,比如对于stream来源的空判断处理,今天我就给大家整理了一些工具…

    Java 2023年6月5日
    071
  • Centos7 编译安装Nginx

    升级系统所有软件 yum -y update 安装Nginx编译所需要的依赖项 yum -y install gcc gcc-c++ make zlib-devel pcre-de…

    Java 2023年5月30日
    050
  • JSP学习笔记

    jsp的全称是java server pages。其主要作用是代替Servlet程序回传html页面的数据。 JSP的本质 JSP页面本质是一个Servlet程序。当我们第一次访问…

    Java 2023年6月8日
    065
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球