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();
    }
}
相关推荐
虫小宝22 分钟前
如何在Java中实现PDF生成
java·开发语言·pdf
菜鸡且互啄691 小时前
在线教育平台,easyexcel使用案例
java·开发语言
八月林城1 小时前
JAVA导出数据库字典到Excel
java·数据库·excel
电饭叔2 小时前
《python程序语言设计》2018版第5章第52题利用turtle绘制sin函数
开发语言·python
weixin_452600692 小时前
如何为老化的汽车铅酸电池充电
开发语言·单片机·安全·汽车·电机·电源模块·充电桩
浅念同学3 小时前
算法-常见数据结构设计
java·数据结构·算法
Java资深爱好者3 小时前
如何在std::map中查找元素
开发语言·c++
YCCX_XFF213 小时前
ImportError: DLL load failed while importing _imaging: 操作系统无法运行 %1
开发语言·python
哥廷根数学学派4 小时前
基于Maximin的异常检测方法(MATLAB)
开发语言·人工智能·深度学习·机器学习
杰哥在此5 小时前
Java面试题:讨论持续集成/持续部署的重要性,并描述如何在项目中实施CI/CD流程
java·开发语言·python·面试·编程