线程池--JAVA

虽然线程是轻量级进程,但是如果当创建和销毁的的频率非常之高,那么它也就会消耗很多的资源。

而线程池就是用来优化线程频繁创建和销毁的场景,减少线程创建、销毁的频率。

ExecutorService

JAVA标准库为我们实现了线程池,ExecutorService是一个接口,线程池的创建并不像平常的接口实现那样直接new,而是使用了“工厂模式”。

public static void main(String[] args) {
    //创建有4个线程的线程池
    ExecutorService service = Executors.newFixedThreadPool(4);
    //创建一个可以根据任务数量 来自行调整线程数量 的线程池
    ExecutorService service1 = Executors.newCachedThreadPool();
    //创建含有一个线程的线程池
    ExecutorService service2 = Executors.newSingleThreadExecutor();
    //创建一个含有3个线程的线程池,该线程池可以调度命令在给定时间后延迟运行
    ScheduledExecutorService service3 = Executors.newScheduledThreadPool(3);
}

创建好了之后可以利用submit()方法来给里面添加任务

public static void main(String[] args) {
    //创建有4个线程的线程池
    ExecutorService service = Executors.newFixedThreadPool(4);
    //添加5个任务
    for (int i = 0; i < 5; i++) {
        int a = i;
        service.submit(()->{
            System.out.println(a);
        });
    }
}

但是第四种创建线程池的方法有点特殊如果你想要实现延时执行任务就需要使用schedule

()方法。

public static void main(String[] args) {
        // 创建一个定时执行任务的线程池,设置核心线程数为3
        ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
        //打印当前时间
        System.out.println(System.currentTimeMillis());
        // 定时执行任务,延迟2秒后开始执行
        service.schedule(() -> {
            // 执行的任务逻辑
            System.out.println("任务执行时间:" + System.currentTimeMillis());
        }, 2, TimeUnit.SECONDS);
}

上述这几个创建线程池的方法本质上都是将ThreadPoolExecutor进行了封装。

ThreadPoolExecutor

这个类有4中构造方法,可是仔细看就会发现前三种还是调用的的四种,所以本质上是只有一种。

各个参数的含义

corePoolSize

当前线程池中的核心线程数即当前线程池在空闲时含有的线程数量,也就是当前线程池包含的线程最少数量。

maximumPoolSize

当前线程池中允许存在的最大线程数。

keepAliveTime

当实际线程数大于核心线程数时,多余的空闲线程能够存活的最长时间。

unit

存活时间的单位。

NANOSECONDS:千分之一微秒;

MICROSECONDS:千分之一毫秒;

MILLISECONDS:千分之一秒;

SECONDS:秒;

MINUTES:分钟;

HOURS:小时;

DAYS:天;

workQueue

用于保存待执行任务的队列。

threadFactory

创建新线程时所用的工厂类。

handler

当线程池中的任务满了之后所使用的拒绝策略。

ThreadPoolExecutor.AbortPolicy:直接抛出异常;

ThreadPoolExecutor.CallerRunsPolicy:新添加的任务,由添加任务的线程执行;

ThreadPoolExecutor.DiscardOldestPolicy :丢弃队列中最老的任务,再将新任务添加进任务队列;

ThreadPoolExecutor.DiscardPolicy:丢弃新添加的任务。

线程池的关闭

想要关闭线程池需要使用shutdown()方法

public static void main(String[] args) {
    // 创建一个定时执行任务的线程池,设置核心线程数为3
    ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
    //打印当前时间
    System.out.println(System.currentTimeMillis());
    // 定时执行任务,延迟2秒后开始执行
    service.schedule(() -> {
        // 执行的任务逻辑
        System.out.println("任务执行时间:" + System.currentTimeMillis());
    }, 2, TimeUnit.SECONDS);
}

可以看出任务执行完后程序并没有退出。

public static void main(String[] args) {
    // 创建一个定时执行任务的线程池,设置核心线程数为3
    ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
    //打印当前时间
    System.out.println(System.currentTimeMillis());
    // 定时执行任务,延迟2秒后开始执行
    service.schedule(() -> {
        // 执行的任务逻辑
        System.out.println("任务执行时间:" + System.currentTimeMillis());
    }, 2, TimeUnit.SECONDS);

    //主线程休眠一段时间
    try {
        Thread.sleep(2000); // 休眠2秒
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    // 关闭线程池
    service.shutdown();
}

接下来为了更好的理解线程池,下面是模拟实现一个含有固定线程数的线程池。

模拟实现

先创建一个类名为MyThreadPool里面含有一个属性,类型为BlockingQueue。

public class MyThreadPool {
    //队列大小为5
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5);
}

写一个只有一个参数的有参构造方法,参数为线程池的线程数。

利用循环创建n个线程,每个线程都不断地从队列中拿任务。

public MyThreadPool(Integer n) {
    for (int i = 0; i < n; i++) {
        Thread t = new Thread(()->{
            while(true) {
                try {
                    Runnable runnable = queue.take();
                    runnable.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
    }
}

写一个submit()方法可以给队列中添加任务。

public void submit(Runnable runnable) {
    try {
        this.queue.put(runnable);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

此时一个简单的线程池就完成了,下面来进行一下简单的测试:

public static void main(String[] args) {
    MyThreadPool myThreadPool = new MyThreadPool(5);
    for (int i = 0; i < 40; i++) {
        int a = i;
        myThreadPool.submit(()->{
            System.out.println(a);
        });
    }
}

完整代码

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

//线程池
public class MyThreadPool {
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5);

    public MyThreadPool(Integer n) {
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(()->{
                while(true) {
                    try {
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            t.start();
        }
    }

    public void submit(Runnable runnable) {
        try {
            this.queue.put(runnable);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/340733.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

archlinux 如何解决安装以后没有声音的问题

今天安装完archlinux以后发现看视频没声音 检查一下是否有 /lib/firmware/intel/sof 发现没有 如果你也是这样的话&#xff0c;可以尝试安装&#xff1a; sudo pacman -S sof-firmware 重启后再看看有没有声音&#xff1a; reboot 反正我有声音了

跟着我学Python进阶篇:03. 面向对象(下)

往期文章 跟着我学Python基础篇&#xff1a;01.初露端倪 跟着我学Python基础篇&#xff1a;02.数字与字符串编程 跟着我学Python基础篇&#xff1a;03.选择结构 跟着我学Python基础篇&#xff1a;04.循环 跟着我学Python基础篇&#xff1a;05.函数 跟着我学Python基础篇&#…

【ARM 嵌入式 编译系列 7.3 -- GCC 链接脚本中 DISCARD 与 .ARM.exidx】

请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 背景.ARM.exidx方法一:使用链接器脚本方法二:使用链接器选项注意事项背景 在移植 RT-Thread 到 cortex-m33(RA4M2)上的时候,在编译的时候遇到下面问题: Building target: ra4m2.elf arm

Vue2基础-Vue对象进阶介绍2

文章目录 一、自定义指令1、用法2、注意点 二、生命周期1、概念2、示意图3、分析 一、自定义指令 本质上是封装了DOM元素的具体操作 1、用法 <div >放大十倍后的值是&#xff1a;<span v-big"n"></span></div> <input type"text&…

【Linux】—— 共享内存

本期我将要带大家学习的是有关进程间通信的另一种方式——共享内存。共享内存是一种用于进程间通信的高效机制&#xff0c;允许多个进程访问和操作同一块内存区域。 目录 &#xff08;一&#xff09;深刻理解共享内存 1.1 概念解释 1.2 共享内存原理 1.3 共享内存数据结构 …

Spring | Srping AOP (AOP简介、动态代理、基于“代理类”的AOP实现)

目录: 1.Spring AOP简介1.1 AOP简介1.2 AOP术语 2.动态代理2.1 JDK动态代理2.2 CGLIB代理 3.基于“代理类”的AOP实现3.1 Spring的通知类型3.2 ProxyFactoryBean ( 可通知.xml配置文件完成aop功能 ) 1.Spring AOP简介 1.1 AOP简介 Spring的AOP模块&#xff0c;是Spring框架体系…

【C++】list容器迭代器的模拟实现

list容器内部基本都是链表形式实现&#xff0c;这里的迭代器实现的逻辑需要注意C语言中指针的转换。 list容器如同数据结构中的队列&#xff0c;通常用链式结构进行存储。在这个容器中&#xff0c;我们可以模仿系统的逻辑&#xff0c;在头结点后设置一个“ 哨兵 ”&#xff0c;…

什么勒索攻击,应该如何防护?

当前&#xff0c;勒索攻击、僵尸网络攻击、DDos攻击、APT攻击、挖矿攻击、供应链攻击、网站攻击、电信诈骗等各种攻击手段层出不穷。 勒索攻击应该是今年网络安全行业讨论最多的话题&#xff0c;勒索钱财或者窃取商业数据是黑产最主要的目的。 勒索软件的攻击特征 与其它攻击行…

限价单和止损单是什么?澳福实例讲解

什么是限价单和止损单&#xff0c;投资者如何使用它?了解交易基础知识&#xff0c;快速进入市场盈利收场&#xff0c;今天fpmarkets澳福和各位投资者继续探讨交易基础知识。 止损单是在看涨趋势中以更高的价格买入的前提&#xff0c;通过图表得知&#xff0c;黄线显示欧元兑美…

刷题 ------ 排序

文章目录 1.K 次取返后最大化的数组和&#xff08;堆&#xff09;2.数组的相对排序&#xff08;桶&#xff09;3.最小绝对差4.根据数字二进制下1的数目排序&#xff08;qsort&#xff09;5.有多少小于当前数字的数字6.非递增顺序的最小子序列7.按照频率将数组升序排序&#xff…

生成当天递增唯一的流水号的几种方式

说明&#xff1a;当开发中&#xff0c;如交易、文件传输过程中的文件名&#xff0c;可能需要我们使用一串唯一的数字来锁定这一条“交互记录”&#xff0c;即流水号。 本文介绍几种生成6位递增唯一&#xff0c;且每日重置的流水号的方式。 方式一&#xff1a;使用Redis 我们…

Leetcode—22.括号生成【中等】

2023每日刷题&#xff08;七十九&#xff09; Leetcode—22.括号生成 算法思想 实现代码 class Solution { public:vector<string> generateParenthesis(int n) {vector<string> ans;int m n * 2;string path(m, 0);function<void(int, int)> dfs [&…

自己构建webpack+vue3+ts

先看看我的目录结构&#xff08;我全局使用TS&#xff09;&#xff1a; 一、安装配置webpack打包 安装esno npm install esnoesno 是基于 esbuild 的 TS/ESNext node 运行时,有了它&#xff0c;就可以直接通过esno *.ts的方式启动脚本&#xff0c;package.json中添加 type:…

力扣62. 不同路径

动态规划 思路&#xff1a; 定义 dp[r][c] 为到达坐标 (r, c) 的路径数&#xff1a; 它只能有同一行左边相邻方格向右到达或者同一列上方相邻方格向下到达&#xff1b;状态转移方程&#xff1a; dp[r][c] dp[r][c - 1] dp[r - 1][c]初始状态 dp[0][0] 1第一行的路径数是 1第…

二维码地址门牌管理系统:社区新风向

文章目录 前言一、集成先进技术的系统二、便捷居民体验三、支持社区管理四、未来展望与可扩展性 前言 随着科技的不断发展&#xff0c;智能化管理已经深入到我们的生活中。二维码门牌管理系统作为一款创新产品&#xff0c;在社区管理领域迅速引起广泛关注。这款系统不仅提升了…

CTFhub-bak文件

CTFhub-Web-信息泄露-备份文件下载-bak文件 题目信息 解题过程 看到提示说和index.php有关&#xff0c;在url后面加index.php.bak&#xff0c;跳转到http://challenge-7a4da2076cfabae6.sandbox.ctfhub.com:10800/index.php.bak网址&#xff0c;即&#xff1a; 跳转到下载页…

彻底搞定让人头痛的nginx location 路径匹配规则

nginx location 路径匹配规则 一、前言二、说在前面三、开始表演 一、前言 很多同学&#xff0c;在配置nginx的时候&#xff0c;都会遇到一个头痛的问题&#xff0c;就是location 的路径应该怎么写&#xff1f;到底要不要加斜杠&#xff0c;有点傻傻分不清楚。今天就来帮助大家…

蓝桥杯真题(Python)每日练Day3

题目 题目分析 为了找到满足条件的放置方法&#xff0c;可以带入总盘数为2和3的情景&#xff0c;用递归做法实现。 A中存在1 2两个盘&#xff0c;为了实现最少次数放入C且上小下大&#xff0c;先将1放入B&#xff0c;再将2放入C&#xff0c;最后将1放入C即可。同理当A中存在1 …

柔性数组和C语言内存划分

柔性数组和C语言内存划分 1. 柔性数组1.1 柔性数组的特点&#xff1a;1.2 柔性数组的使用1.3 柔性数组的优势 2. 总结C/C中程序内存区域划分 1. 柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array)这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff…

以太坊账户地址与比特B地址生成方法对比

作者 张群&#xff08;赛联区块链教育首席讲师&#xff0c;工信部赛迪特聘资深专家&#xff0c;CSDN认证业界专家&#xff0c;微软认证专家&#xff0c;多家企业区块链产品顾问&#xff09;关注张群&#xff0c;为您提供一站式区块链技术和方案咨询。 以太坊和比特B地址在生成方…