线程进阶:生产者消费者模式和线程池

2023-05-16

一、生产者消费者模式

这是一种不属于GOF23的设计者模式

这种模式分为三个对象:一个生产者,一个消费者,一个缓存区。

  • 生产者

某些程序/进程/线程负责生产数据就属于生产者

  • 消费者

某些程序/进程/线程负责使用数据就属于消费者

假设在生产者和消费者之间没有一个缓存区,那么会出现什么情况呢?

  1. 耦合性高,生产者和消费者联系紧密,不利于系统的扩展和维护
  2. 并发性能低,同时能处理请求量少
  3. 忙闲不均,生产者和消费者的速度不一致,带来系统资源的浪费

那么如果有一个缓存区,那么两者之间的依赖性就大大降低,也就是解耦。同时生产者也可以生产多个资源放到缓存区,消费者也可以从缓存区多次得到资源,提高并发性能。阻塞队列可以很好的解决忙闲不均的问题。

阻塞队列

能够根据数据满或空的情况,自动对线程执行等待和通知

BlockingQueue 接口

  • put 添加数据,达到上限会自动让线程等待

  • take 取并删除数据,数据空了会自动让线程等待

实现类

ArrayBlockingQueue 类 数据结构为数组

LinkedBlockingQueue类 链表结构

我们这里举一个简单的例子解释一下这个模式:

比方说,早上我们都要去买包子吃早饭,那么包子师傅就是生产者,顾客就是消费者,蒸笼就是缓存区。大家都知道,蒸笼是可以由包子师傅自己决定有多少个,因此缓存区的最大值就可以自己进行设置。包子师傅(生产者)可以一次做多个包子(资源)放到蒸笼(缓存区)里,当有顾客(消费者)来购买包子(拿资源)就是从蒸笼里面拿取包子。蒸笼满了,包子师傅就不会做包子了,顾客也会来买包子;蒸笼空了,包子师傅就会继续做包子,顾客如果就喜欢吃他家的包子,那么就会等着,直到包子做好买完才离开。

代码如下:

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

public class BaoziShop2 {
    static class Baozi {
        //定义包子id
        private int id;

        public Baozi(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "包子-->" + id;
        }
    }

    public static void main(String[] args) {
        BaoziShop2 baoziShop = new BaoziShop2();
        /**
         * 阻塞队列
         * 蒸笼内包子上限是100个
         */
        BlockingQueue baoziList = new ArrayBlockingQueue(100);

        /**
         * 生产者线程
         * 当到达100个的时候,这条线程就会自动进行堵塞
         */
        new Thread(() -> {
            for (int i = 0; i < 200; i++) {
                Baozi baozi = new Baozi(baoziList.size());
                System.out.println(Thread.currentThread().getName() + "生产了" + baozi);
                try {
                    baoziList.put(baozi);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        /**
         * 消费者线程
         * 5个人买包子
        */
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                //每个人买10个包子
                for (int j = 0; j < 10; j++) {
                    try {
                        Baozi baozi = (Baozi) baoziList.take();
                        System.out.println(Thread.currentThread().getName()+"购买了"+baozi);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

二、线程池

线程池的功能与作用

线程池会保存一定量的线程,线程执行完任务后,会回到线程池中,等待下一个任务,节省系统资源,提升性能。

那为什么要使用线程池呢?

首先线程是一种宝贵的系统资源,执行完任务后会死亡,如果有大量任务需要处理,需要频繁的创建和销毁线程,造成系统性能降低。

线程池的使用

顶层接口:Executor(里面只有一个方法)

  • execute(Runnable) 启动线程执行一个任务

ExecutorService

继承了Executor接口,对功能进行了增强添加

Executors

是一个工具类,能够更加方便的创建线程池

主要的方法

方法名说明
newCachedThreadPool()创建长度不限的线程池
newFixedThreadPool(int )创建固定长度的线程池
newSingleThreadExecutor()创建单一个数的线程池
newScheduledThreadPool(int)创建可以调度的线程池
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ThreadPoolDemo {

    public static void useCachedThreadPool(){
        //创建长度不限的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            int n = i;
            //使用线程池启动线程
            executorService.execute(()->{
                System.out.println(Thread.currentThread().getName()+"执行了任务" + n);
            });
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.shutdown();
    }

    public static void useFixedThreadPool(){
        //创建长度固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 100; i++) {
            int n = i;
            //使用线程池启动线程
            executorService.execute(()->{
                System.out.println(Thread.currentThread().getName()+"执行了任务"+n);
            });
        }
        executorService.shutdown();
    }

    public static void useSingleThreadPool(){
        //创建单一长度的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 100; i++) {
            int n = i;
            //使用线程池启动线程
            executorService.execute(()->{
                System.out.println(Thread.currentThread().getName()+"执行了任务"+n);
            });
        }
        executorService.shutdown();
    }

    public static void useScheduledThreadPool(){
        //获得可调度的线程池
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        //执行可调度任务
        System.out.println("------------");
        scheduledExecutorService.scheduleAtFixedRate(()->{
            System.out.println(Thread.currentThread().getName()+"---->"+ LocalDateTime.now());
        },1,3, TimeUnit.SECONDS);
    }

    public static void main(String[] args) {
//        useCachedThreadPool();
//        useFixedThreadPool();
//        useSingleThreadPool();
//        useScheduledThreadPool();
    }
}

线程池的优化配置

线程池的实现类

ThreadPoolExecutor

线程池的构造方法参数:

  • corePoolSize 核心线程数,创建线程池后自带线程,不会进行销毁

  • maximumPoolSize 最大线程数

  • keepAliveTime 存活时间,非核心线程能够闲置的时间,超过后被销毁

  • timeUnit 时间单位

  • blockingQueue 阻塞队列 存放任务(Runnable)的集合

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

线程进阶:生产者消费者模式和线程池 的相关文章

  • python 读写文件 删除文件

    概述 xff1a 主要内容 python read write 删除文件写 xff1b 在 39 w 39 和 39 a 39 模式下 xff0c 如果你打开的文件不存在 xff0c 那么open 函数会自动帮你创建一个 1 写入和读取文件
  • 看完微信抢红包算法你就明白,为啥你不是手气最佳

    摘要 xff1a 今天我们就来分析一下抢红包的算法 xff0c 其中有一些是微信红包的算法 xff0c 看完你就知道手气最佳是如何产生的啦 本文分享自华为云社区 为啥春节抢红包总不是手气最佳 xff1f 看完微信抢红包算法你就明白了 xff
  • python读音播报-基于python GUI开发的点名小程序(语音播报)

    实现名单轮播 点名 语音播报功能 coding utf8 ProjectName python3 FileName name Author shuxiaying Date 2020 7 9 Description import dateti
  • python编程100个小程序-整理了适合新手的20个Python练手小程序

    即刻关注公众号 xff0c 发现世界的美好 100个Python练手小程序 xff0c 学习python的很好的资料 xff0c 覆盖了python中的每一部分 xff0c 可以边学习边练习 xff0c 更容易掌握python 程序1 题目
  • python编程入门书籍-最适合Python初学者的6本书籍推荐「必须收藏」

    原标题 xff1a 最适合Python初学者的6本书籍推荐 必须收藏 Python是一种通用的解释型编程 xff0c 主要用于Web开发 机器学习和复杂数据分析 Python对初学者来说是一种完美的语言 xff0c 因为它易于学习和理解 x
  • dubbo好书推荐

    为了自己的进步 xff0c 也为了能够帮助其他人 xff0c 我决定开始写一些东西 xff0c 网上有很多学习资料 xff0c 自己的功力未必到家 xff0c 所以大家共同进步吧 xff01 站在巨人的肩膀上看得远 xff0c 现在推荐一本
  • linux升级java的jdk版本

    这里以升级jdk 8u231 linux x64 rpm为示例 安装 xff0c rpm ivh jdk 8u161 linux x64 rpmrpm pql root jdk 8u161 linux x64 rpm 通过查看 jdk 的信
  • you-get简明使用教程

    前言 近期 xff0c 想要下载哔哩哔哩等网站的视频 xff0c 网上查了一下you get的使用教程和视频 xff0c 有些特别简单 xff0c 说的不求甚解 xff0c 有些讲的太过繁琐 xff0c 所以 xff0c 打算自己写一个简单
  • linux分区扩容(非lvm)

    前言 最近 xff0c 在使用linux中中 xff0c 对于分区空间不够使用的情况下 xff0c 如果是使用lvm的分区 xff0c 是可以使用lvm扩容的 xff0c 流程大概是 xff1a 新加磁盘 将新加的磁盘创建成pv 将新加的p
  • linux关闭virbr0网卡

    前言 最近 xff0c 在使用linux时 要求需要关闭virbr0的网卡 xff0c 网上查了一下virbr0是kvm虚拟机使用的网卡 xff0c 是libvirtd服务安装后 xff0c 自动生成的 xff0c virbr0的配置文件位
  • rsync定时备份数据

    前言 rsync定时备份数据 简介 使用非系统用户备份数据192 168 130 63的 var www html 目录到192 168 130 64的 web bak目录 rsync定时备份数据 实验环境 xff1a 服务器 xff1a
  • rsync+sersync实时同步数据

    前言 rsync 43 sersync实时同步数据 简介 rsync 43 sersync实时同步数据的原理是在客户端安装sersync监控目录的变化 xff0c 一般是增删改 xff0c 检测到变化以后 xff0c 将变化的文件同步到服务
  • 配置 NFS 服务简述

    前言 配置 NFS 服务简述 简介 nfs utils服务依赖于rpcbind的服务 xff0c 是将服务端的目录共享 xff0c 其实是共享的 整个服务端的空间 xff0c 在客户端将共享目录挂载使用即可 配置 NFS 服务简述 实验环境
  • javaweb中四大域对象的生命周期与常用方法

    一 ServletContext 1 生命周期 xff1a 当Web应用被加载进容器时创建代表整个web应用的ServletContext对象 xff0c 当服务器关闭或Web应用被移除时 xff0c ServletContext对象跟着销
  • spring boot 集成 Guava Cache

    Guava Cache 背景集成缓存存放缓存回收 xff1a 基于容量回收 xff08 Size based Eviction xff09 基于时间回收 xff08 Timed Eviction xff09 基于引用类型的回收 xff08
  • 求1~n的阶乘的和,例:1!+2!+3!+......n!

    目录 递归实现 思想 代码实现 非递归实现 思想 代码实现 递归实现 xff1a 利用递归的形式实现阶乘的求和功能 xff0c 但是要注意栈溢出 xff0c 每次递归都会调用 xff0c 都会压栈 xff0c 占用栈中内存 xff0c 如果
  • 如何给shell脚本传入参数小结

    大家都知道普通的bash命令后边可以跟任意的参数 xff0c 那我们自己编写的脚本是否也支持传递参数呢 xff1f 答案当然是肯定的 执行 vim test sh 创建一个新的shell脚本 脚本test sh的内容如下 xff1a bin
  • 使用calibre制作带目录的mobi电子书

    1 把word等格式的书籍转换成txt格式的文件 xff0c 另外再重新把txt文件打开 xff0c 另存为UTF 8格式的文件 2 在想设为目录条目的地方输入 符号 xff0c 一级目录输入一个 xff0c 二级目录输入 3 在每段开头处
  • redis的快照和集群部署

    1 安装 使用redis 3 2 8 tar gz tar zxvf redis 3 2 8 tar gz cd redis 3 2 8 make amp amp make test amp amp make install xff08 1
  • 解决cannot open shared object file: No such file or directory

    一 linux下调用动态库 so文件时提示 xff1a cannot open shared object file No such file or directory 解决办法 xff1a 1 此时ldd xxx查看依赖缺少哪些库 lib

随机推荐

  • Activity的启动模式以及onNewIntent和onConfigurationChanged这两个生命周期方法的场景

    1 Activity的启动模式有哪几种 xff0c 分别用于什么场景 xff1f Activity的启动模式的4种 xff1a standard标准启动模式 xff0c 默认的启动模式 每一次启动这个activity都会创建新的activi
  • node 第三方模块系列------minimist轻量级的命令行参数解析引擎

    总体介绍 xff1a node js的命令行参数解析工具有很多 xff0c 比如 xff1a argparse optimist yars commander optimist和yargs内部使用的解析引擎正是minimist xff0c
  • Python教程:文件路径/目录获取教程

    一 获取文件路径实现 1 获取当前文件路径 span class token keyword import span os current file path span class token operator 61 span file s
  • npm的安装及缓存机制详解

    npm的安装机制 下面我们会通过一个流程图来具体学习npm install的安装机制 npm install执行之后 首先会检查和获取 npm的配置 这里的优先级为 项目级的 npmrc文件 gt 用户级的 npmrc文件 gt 全局级的
  • s7epaapidll丢失怎么办_s7epaapidll下载

    s7epaapi dll找不到怎么修复 xff1f 很多用户玩单机游戏或者安装软件的时候就出现过这种问题 xff0c 如果是新手第一时间会认为是软件或游戏出错了 xff0c 其实并不是这样 xff0c 其主要原因就是你电脑的该dll文件没有
  • 01-Elasticsearch安装与配置

    一 Elasticsearch 介绍 Elasticsearch是一个实时分布式搜索和分析引擎 二 运行环境 系统 Centos 7JDK 1 8ES版本 7 5 1 下载地址 https www elastic co cn downloa
  • 01-Liunx_用户操作

    一 创建用户组 创建用户组 root 64 localhost bin groupadd 用户组名称 example groupadd test 删除用户组 root 64 localhost bin groupdel 用户组名称 exam
  • 打工与乘公交

    去一个公司打工就如同上了一辆公交车 在上车之前 xff0c 你应该清楚自己打算去哪里 xff0c 打算在哪里下车 有的公交车很豪华 xff0c 有的很破烂 xff0c 但是这并不是重点 xff0c 所有能开到目的地的车都是好车 上了车之后
  • 01-MyBatis Plus-配置信息

    一 官网 URL https mp baomidou com 二 特性 无侵入 xff1a 只做增强不做改变 xff0c 引入它不会对现有工程产生影响 xff0c 如丝般顺滑损耗小 xff1a 启动即会自动注入基本 CURD xff0c 性
  • 五分钟教你手写HashMap

    原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 85927183 本文归作者 老铁123 和博客园共有 xff0c 欢迎转载 xff0c 但未经作者同意必
  • Java实现快速排序算法

    原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 85949755 本文归作者 老铁123 和博客园共有 xff0c 欢迎转载 xff0c 但未经作者同意必
  • 手写ArrayBlockingQueue

    个人分类 xff1a 算法 编辑 原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 88363745 本文归作者 老铁123 和博客园共有 xff0c 欢迎
  • 手写LinkedBlockingQueue

    原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 88364742 本文归作者 老铁123 和博客园共有 xff0c 欢迎转载 xff0c 但未经作者同意必
  • Viewbinding自动生成XML的一个对应绑定类

    当你在项目 Module 的build gradle中的android 中设置 buildFeatures viewBinding true 设置完sync一下 xff0c 然后会在项目中看到对应的XML文件的一个继承了ViewBindin
  • AE制作Json动画教程

    本文将从为什么要做动画 xff0c 到动画实现方式 xff0c 再到用AE 43 Bodymovin制作动画 xff0c 结合实际案例行分享 xff0c 希望给新手带来一些启发 首先我们来聊聊 xff0c 我们为什么要做动效 xff1f 1
  • zabbix proxy 表分区

    zabbix server进行表分区的话 xff0c zabbix的内部管家会失效 xff0c 这个时候 xff0c 如果有proxy的话 xff0c 也要进行表分区 xff0c proxy表分区比较简单 xff0c 也不用每天更换分区 步
  • pycharm中unresolved reference怎么解决(配置问题)

    iunresolved reference怎么解决 解决方法 xff1a xff08 本人使用方法二解决的 xff09 方法1 进入PyCharm gt Settings gt Build Excution Deployment gt Co
  • ModuleNotFoundError: No module named ‘_ssl‘

    如果openssl是自己编译安装的 xff0c 安装python时需要注意以下问题 xff1a 从python官网下载的tar gz包或者tgz解压 xff1a 更改 xff1a Python 3 6 6 Modules Setup dis
  • Can I become a good programmer without math and algorithms knowledge?

    Knowledge of algorithms has very little to do with programming skill As some random dude on the internet once said 34 Wh
  • 线程进阶:生产者消费者模式和线程池

    一 生产者消费者模式 这是一种不属于GOF23的设计者模式 这种模式分为三个对象 xff1a 一个生产者 xff0c 一个消费者 xff0c 一个缓存区 生产者 某些程序 进程 线程负责生产数据就属于生产者 消费者 某些程序 进程 线程负责