Java SE入门及基础(62)& 线程池 & 执行器

线程池

**1.**执行器

In all of the previous examples, there's a close connection between the task being done by a new thread, as defined by its Runnable object, and the thread itself, as defined by a Thread object. This works well for small applications, but in large-scale applications, it makes sense to separate thread management and creation from the rest of the application. Objects that encapsulate these functions are known as executors.
在前面的所有示例中,由新线程(由其Runnable 对象定义)执行的任务与由 Thread 对象定义的线程本身之间存在紧密的联系。 这对于小型应用程序非常有效,但是在大型应用程序中,将线程管理和创建与其余应用程序分开是有意义的。 封装这些功能的对象称为执行器。

Executor接口方法

void execute ( Runnable command ); // 将任务添加到线程池中,等待线程池调度执行

ExecutorService接口常用方法

void shutdown (); // 有序关闭线程池,不再接收新的线程任务,但池中已有任务会执行
List < Runnable > shutdownNow (); // 关闭线程池,尝试停止所有正在执行的任务,并将池中等待执行的任务返回
boolean isShutdown (); // 检测线程池是否已经关闭
boolean isTerminated (); // 检测线程池是否已经终止
Future <?> submit ( Runnable task ); // 提交一个任务至线程池中

**2.**线程池

Most of the executor implementations in java.util.concurrent use thread pools, which consist of worker threads. This kind of thread exists separately from the Runnable and Callable tasks it executes and is often used to execute multiple tasks.
java.util.concurrent中的大多数执行程序实现都使用线程池,该线程池由工作线程组成。这种线程与它执行的Runnable 和 Callable 任务分开存在,通常用于执行多个任务。
Using worker threads minimizes the overhead due to thread creation. Thread objects use a significant amount of memory, and in a large-scale application, allocating and deallocating many thread objects creates a significant memory management overhead.
使用工作线程可以最大程度地减少线程创建所带来的开销。线程对象占用大量内存,在大型应用程序中,分配和取消分配许多线程对象会产生大量内存管理开销。
One common type of thread pool is the fixed thread pool. This type of pool always has a specified number of threads running; if a thread is somehow terminated while it is still in use, it is automatically replaced with a new thread. Tasks are submitted to the pool via an internal queue, which holds extra tasks whenever there are more active tasks than threads.
线程池的一种常见类型是固定线程池。这种类型的池始终具有指定数量的正在运行的线程。如果某个线程在仍在使用时以某种方式终止,则它将自动替换为新线程。任务通过内部队列提交到池中,该内部队列在活动任务多于线程时容纳额外的任务。
An important advantage of the fixed thread pool is that applications using it degrade gracefully.
固定线程池的一个重要优点是使用该线程池的应用程序可以正常降级

线程池构造方法

public ThreadPoolExecutor ( int corePoolSize , // 核心线程数
int maximumPoolSize , // 最大线程数
long keepAliveTime , // 工作线程存活时间
TimeUnit unit , // 时间单位
BlockingQueue < Runnable > workQueue , // 任务队列
ThreadFactory threadFactory , // 线程工厂
RejectedExecutionHandler handler ) // 拒绝处理器

示例
复制代码
import java.util.Queue;
import java.util.concurrent.*;
public class ThreadPoolTest {
    public static void main(String[] args) {
        LinkedBlockingDeque<Runnable> taskQueue = new LinkedBlockingDeque<>
                (10);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                5, //核心线程数
                10, //最大工作线程数
                2,//非核心线程的工作线程存活时间
                TimeUnit.SECONDS,//存活时间单位
                taskQueue,//任务队列
                Executors.defaultThreadFactory(),//线程池中的线程创建工厂
                new ThreadPoolExecutor.AbortPolicy());//拒绝新线程任务的策略
        for(int i=0; i<30; i++){
            pool.submit(new ThreadPoolTask(i));
            int corePoolSize = pool.getCorePoolSize();//获取核心线程数
            int size = pool.getQueue().size(); //获取队列中任务个数
            long finish = pool.getCompletedTaskCount();//获取线程池执行完成任务
            的个数
            System.out.printf("线程池中核心线程数:%d,队列中任务个数:%d,线程池完
                    成任务数:%d\n",
            corePoolSize, size, finish);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        pool.shutdown();//关闭线程池,等待线程池中的任务执行完成,但是不会接收新的线程
        任务
    }
    static class ThreadPoolTask implements Runnable{
        private int num;
        public ThreadPoolTask(int num) {
            this.num = num;
        }
        @Override
        public void run() {
            System.out.println("正在执行线程任务" + num);
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
线程池工作流程

线程池启动后,核心线程就已经启动,当一个新的任务提交到线程池时,首先会检测当前是否存在空闲的核心线程,如果存在,就将该任务交给这个空闲核心线程执行。如果不存在,那么就将该任务交给队列,在队列中排队等候。如果队列满了,此时线程池会检测当前工作线程数是否达到最大线程数,如果没有达到最大线程数,那么将由线程工厂创建新的工作线程来执行队列中的任务,这样,队列中就有空间能够容纳这个新任务。如果创建的工作线程在执行完任务后,在给定的时间范围内没有新的任务执行,这些工作线程将死亡。如果已经达到最大线程数,那么线程池将采用提供的拒绝处理策略来拒绝这个新任务。

线程池创建方式
复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorTest {
    public static void main(String[] args) {
//创建一个给定核心线程数以及最大线程数的线程池,该线程池队列非常大
        ExecutorService pool1 = Executors.newFixedThreadPool(5);
//创建只有一个核心线程数以及最大线程数的线程池,该线程池队列非常大
        ExecutorService pool2 = Executors.newSingleThreadExecutor();
//创建一个核心线程为0,最大线程数为整数的最大值的可缓存的线程池
        ExecutorService pool3 = Executors.newCachedThreadPool();
//创建一个给定核心线程数,最大线程数为整数的最大值的可调度的线程池
        ExecutorService pool4 = Executors.newScheduledThreadPool(5);
    }
}

**3.**线程池的使用

复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorTaskTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 100; i++) {
            int order = i;
            service.submit(() -> System.out.println("正在执行任务" + order));
        }
        service.shutdown();
    }
}
相关推荐
捕鲸叉17 分钟前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer22 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq24 分钟前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml41 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~1 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616881 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7891 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java2 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
睡觉谁叫~~~2 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust