【多线程】(五)工厂模式和线程池

文章目录

  • 一、工厂模式
  • 二、线程池
    • 2.1 什么是线程池
    • 2.2 Executor 工厂类创建线程池
    • 2.3 ThreadPoolExecutor类创建线程池
  • 三、线程池的实现


一、工厂模式

在Java中,工厂模式是一种创建对象的设计模式,它通过提供一个共同的接口来实例化对象,而不暴露具体实现的细节。工厂模式可以帮助我们解耦对象的创建和使用,提供了一种灵活的方式来创建对象。

在工厂模式中,通常有一个抽象的工厂接口,该接口定义了创建对象的方法。然后,有一个或多个具体的工厂类实现这个接口,每个工厂类负责创建一种具体类型的对象。

下面是一个简单的示例,演示了在Java中如何使用工厂模式:

首先,我们定义一个抽象的产品接口:

public interface Product {void doSomething();
}

然后,我们创建两个具体的产品类,实现产品接口:

public class ConcreteProduct1 implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProduct1 do something");}
}public class ConcreteProduct2 implements Product {@Overridepublic void doSomething() {System.out.println("ConcreteProduct2 do something");}
}

接下来,我们定义一个抽象的工厂接口:

public interface Factory {Product createProduct();
}

然后,我们创建两个具体的工厂类,实现工厂接口:

public class ConcreteFactory1 implements Factory {@Overridepublic Product createProduct() {return new ConcreteProduct1();}
}public class ConcreteFactory2 implements Factory {@Overridepublic Product createProduct() {return new ConcreteProduct2();}
}

最后,我们可以使用工厂来创建具体的产品对象,而不需要直接实例化具体的产品类:

public class Main {public static void main(String[] args) {Factory factory1 = new ConcreteFactory1();Product product1 = factory1.createProduct();product1.doSomething();Factory factory2 = new ConcreteFactory2();Product product2 = factory2.createProduct();product2.doSomething();}
}

运行上述示例,将会输出以下内容:

ConcreteProduct1 do something
ConcreteProduct2 do something

这样,我们通过工厂模式,实现了创建产品对象的过程和具体产品的实现相分离,客户端只需要通过工厂接口创建产品对象,而不需要关心具体的产品类。这种设计模式使得系统更具有灵活性和可扩展性。

二、线程池

2.1 什么是线程池

线程池是Java中的一个重要概念,它是一种管理和复用线程的机制。线程池维护着一个线程队列,其中包含着多个准备好的线程。当有任务需要执行时,线程池中的线程可以被分配来执行任务,执行完成后又可以返回线程池以供下一次使用

引入线程池的主要目的是为了提高系统的性能和资源利用率。以下是引入线程池的一些好处:

  1. 减少线程创建和销毁的开销
  2. 控制并发线程的数量
  3. 提高响应速度和吞吐量
  4. 提供线程管理和监控
  5. 任务队列和调度策略

2.2 Executor 工厂类创建线程池

Java中的java.util.concurrent.Executors类提供了一个工厂方法来创建不同类型的线程池。这个工厂类提供了一些方便的方法来创建常见类型的线程池。以下是一些常用的线程池创建方法:

  1. FixedThreadPool(固定大小线程池):创建一个固定大小的线程池,一旦线程池达到最大线程数量,其他任务会等待。可以使用 Executors.newFixedThreadPool(int nThreads) 方法创建。
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new MyTask()); // 提交任务给线程池执行
executor.shutdown(); // 关闭线程池
  1. CachedThreadPool(缓存线程池):根据需要创建新线程,但如果有空闲线程则复用。如果线程空闲时间超过指定的时间(默认为60秒),则会被终止并从线程池中移除。可以使用 Executors.newCachedThreadPool() 方法创建。
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new MyTask()); // 提交任务给线程池执行
executor.shutdown(); // 关闭线程池
  1. SingleThreadExecutor(单线程线程池):只创建一个线程的线程池,保证所有任务按顺序执行。可以使用 Executors.newSingleThreadExecutor() 方法创建。
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new MyTask()); // 提交任务给线程池执行
executor.shutdown(); // 关闭线程池
  1. newScheduledThreadPool(定时线程池):创建一个固定大小的线程池,可用于执行定时任务和周期性任务。
ExecutorService executor = Executors.newScheduledThreadPool(3);
executor.submit(new MyTask()); // 提交任务给线程池执行
executor.shutdown(); // 关闭线程池

这些线程池的使用方法类似,通过 submit() 方法提交任务给线程池执行,shutdown() 方法用于关闭线程池。可以根据实际需求选择适合的线程池类型,并根据需要调整线程池的大小和配置。

2.3 ThreadPoolExecutor类创建线程池

Executors 本质上是对 ThreadPoolExecutor 类的封装,ThreadPoolExecutor类是ExecutorService接口的实现,它提供了更灵活的线程池创建和配置选项。通过使用ThreadPoolExecutor类,可以自定义线程池的行为、线程数量、任务队列、拒绝策略等。

ThreadPoolExecutor 提供了更多的可选参数,可以进一步细化线程池行为的设定,以下是ThreadPoolExecutor类的构造函数及其说明:

构造函数说明
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)创建一个线程池,具有指定的核心线程数、最大线程数和任务队列,使用默认的拒绝策略。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)创建一个线程池,具有指定的核心线程数、最大线程数、任务队列和拒绝策略。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)创建一个线程池,具有指定的核心线程数、最大线程数、任务队列和线程工厂。线程工厂用于创建线程的实例。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)创建一个线程池,具有指定的核心线程数、最大线程数、任务队列、线程工厂和拒绝策略。线程工厂用于创建线程的实例,拒绝策略用于处理无法执行的任务。

注意:上述构造函数中的参数含义如下:

  • corePoolSize:核心线程数,表示线程池中保持活动状态的线程数量,即使它们处于空闲状态。
  • maximumPoolSize:最大线程数,表示线程池中允许存在的最大线程数量,包括核心线程和非核心线程。
  • keepAliveTime:非核心线程的闲置超时时间,当线程池中的线程数量超过核心线程数时,多余的空闲线程会在指定的时间内被回收。
  • unit:闲置超时时间的单位,例如,TimeUnit.SECONDS表示以秒为单位。
  • workQueue:任务队列,用于存储待执行的任务。
  • threadFactory:线程工厂,用于创建线程的实例。
  • handler:拒绝策略,表示当线程池和任务队列都已满时,新提交的任务如何被拒绝执行。
    • AbortPolicy():超过负荷, 直接抛出异常。
    • CallerRunsPolicy():调用者负责处理。
    • DiscardOldestPolicy():丢弃队列中最老的任务。
    • DiscardPolicy():丢弃新来的任务。

下面是使用ThreadPoolExecutor类创建线程池的示例:

int corePoolSize = 5; // 核心线程数
int maximumPoolSize = 10; // 最大线程数
long keepAliveTime = 60L; // 非核心线程的闲置超时时间
TimeUnit unit = TimeUnit.SECONDS; // 闲置超时时间的单位
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); // 任务队列
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略ExecutorService executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,handler
);

三、线程池的实现

创建一个简单的线程池:

// 自定义线程池
class MyThreadPool{// 任务队列private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();// n 表示线程池数量public MyThreadPool(int n){// 创建n个线程for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {while (true){try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}// 注册任务给线程池public void submit(Runnable runnable){try {queue.put(runnable);} catch (InterruptedException e) {e.printStackTrace();}}
}
  • 以上代码展示了一个简单的自定义线程池实现。该自定义线程池类名为MyThreadPool,通过构造函数传入线程池数量n,并使用一个BlockingQueue作为任务队列来存储待执行的任务。
  • 在构造函数中,创建了n个线程,并在每个线程中使用一个循环来不断从任务队列中取出任务并执行。
  • submit()方法用于向线程池提交任务,将任务放入任务队列中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis【实战篇】---- 分布式锁

Redis【实战篇】---- 分布式锁 1. 基本原理和实现方式对比2. Redis分布式锁的实现核心思路3. 实现分布式锁版本一4. Redis分布式锁误删情况说明5. 解决Redis分布式锁误删问题6. 分布式锁的原子性问题7. Lua脚本解决多条命令原子性问题8. 利用Java代码调试Lua脚本改造分布式锁 1…

css背景毛玻璃效果

一、结论&#xff1a;通过 css 的 backdrop-filter 属性设置滤镜函数 blur 一般会是有 背景色、透明度 的容器&#xff0c;如&#xff1a; /* 宽高等其他设置这里省略没写 */ background:rgba(3, 87, 255, 0.3); backdrop-filter: blur(10px);二、backdrop-filter 的其他用法…

Mysql教程(四):DML学习

Mysql教程&#xff08;四&#xff09;&#xff1a;DML学习 前言 DML-介绍 DML英文全称是Data Manipulation Language数据库操作语言&#xff0c;用来对数据库中表的数据记录进行增删改查。 添加数据&#xff08;INSERT&#xff09;修改数据&#xff08;UPDATE&#xff09;删除…

走访慰问空巢老人,连接传递浓浓温情

为了弘扬中华民族尊老、敬老、爱老的优良传统&#xff0c;让老人们感受到政府和社会的温暖&#xff0c;在“端午”来临之际&#xff0c;思南县青年志愿者协会联合思南县民慈社会工作服务中心、思南县小荧星幼儿园、思南县小英豪幼儿园到大河坝镇天坝村开展“走访慰问空巢老人&a…

docker 安装minIO服务器-以及数据迁移

--------------docker安装minIO-------------- 1.安装docker环境略 2.安装minIO镜像 docker pull minio/minio 3.运行MinIO docker run -p 9000:9000 -p 9090:9090 \ --name minio \ -d --restartalways \ -e "MINIO_ACCESS_KEYadmin" \ -e "MINIO_SECRET…

springboot整合eureka、config搭建注册中心和配置中心

目录 一 、springboot整合eureka实现注册中心 二、springboot整合config实现配置中心 三、从配置中心拉取配置 这篇文章详细介绍怎么通过eureka和config分别搭建一个注册中心和配置中心的服务。 一 、springboot整合eureka实现注册中心 1、创建一个springboot项目&#xff…

LRU 算法,但 get 和 put 必须 O(1),用哈希表

https://leetcode.cn/problems/lru-cache/ 题目有key、value的&#xff0c;直接就上map了 结果&#xff1a;&#x1f605; 仔细一看&#xff0c;原来要 get 和 put 必须 O(1) 只能抛弃树型数据结构了 线性的数据结构也可以吧&#xff0c;如果可以构造出一个队列&#xff0c…

Appium+python自动化(十一)- 元素定位- 下卷超详解)

1、 List定位 List故名思义就是一个列表&#xff0c;在python里面也有list这一个说法&#xff0c;如果你不是很理解什么是list&#xff0c;这里暂且理解为一个数组或者说一个集合。首先一个list是一个集合&#xff0c;那么他的个数也就成了不确定性&#xff0c;所以这里需要用复…

AI一点通:使用Pinecone、Langchain和OpenAI嵌入构建强大的文本搜索系统

在当今数据驱动的世界中&#xff0c;企业和开发人员经常需要实现强大的文本搜索功能。传统的搜索算法在处理大量非结构化文本数据时可能无法提供最优结果。这就是Pinecone、Langchain和OpenAI服务发挥作用的地方。在本博客文章中&#xff0c;我们将探讨设置和利用这些工具来构建…

【InsCode Stable Diffusion 美图活动一期】生成着玩

此为内容创作模板&#xff0c;请按照格式补充内容&#xff0c;在发布之前请将不必要的内容删除 一、 Stable Diffusion 模型在线使用地址&#xff1a; https://inscode.csdn.net/inscode/Stable-Diffusion 二、模型相关版本和参数配置&#xff1a; 三、图片生成提示词与反向…

春秋云境—Initial

文章目录 春秋云境—Initial一、前期准备1、靶标介绍2、相关设备 二、WEB渗透1、ThinkPHP RCE&#xff08;1&#xff09;、打开网站&#xff08;2&#xff09;、检测漏洞 2、蚁剑连接3、sudo提权4、frpc代理5、fsacn扫描 三、后渗透1、信呼OA RCE&#xff08;1&#xff09;、1.…

npm安装依赖报错Unexpected token ‘.‘ 处理

1. 问题 在用nvm切换高版本node版本之后npm install安装项目依赖时报错如下&#xff1a; npm ERR! Unexpected token . 日志信息如下&#xff1a; 报错信息量很少&#xff0c;但是跟高版本node环境下安装依赖有关系。 2. 解决思路 安装低版本的node环境运行项目&#xff…

C++ 多线程编程

1 多线程编程简介 说到多线程编程&#xff0c;就不得不提并行和并发&#xff0c;多线程是实现并发和并行的一种手段。 并行是指两个或多个独立的操作同时进行。 并发是指一个时间段内执行多个操作。 在单核时代&#xff0c;多个线程是并发的&#xff0c;在一个时间段内轮流…

RabbitMQ死信交换机、TTL及延迟队列

一&#xff0c;死信交换机 1&#xff0c;什么是死信交换机 了解死信交换机之前我们先来了解一下什么是死信&#xff0c;当一个队列满足下面的三种情况的时候我们一般称为死信&#xff08;dead letter&#xff09;&#xff1a; 消费者使用basic.reject或 basic.nack声明消费失…

小白入门深度学习 | 6-6:Inception v3 算法原理

一、理论基础 Inceptionv3论文:Rethinking the Inception Architecture for Computer Vision.pdf Inception v3由谷歌研究员Christian Szegedy等人在2015年的论文《Rethinking the Inception Architecture for Computer Vision》中提出。Inception v3是Inception网络系列的第三…

petalinux 无法通过SDK进行TCF调试

IP地址设置没问题 但是无法进行DEBUG 原因是没有开启debug模式&#xff0c;做下图设置重新编译程序生成BOOT.bin即可

追踪 Kubernetes 中的 DNS 查询

在过去的文章中&#xff0c;我们曾 追踪过 Kubernetes 中的网络数据包&#xff0c;这篇文章将追踪 Kubernetes 中的 DNS 查询。 让我们以在 Pod 中解析 Service 完全限定域名&#xff08;FQDN&#xff09; foo.bar.svc.cluster.local 为例。 在开始之前&#xff0c;先回顾下 …

微信小程序的目录解析--【浅入深出系列001外篇】

浅入深出系列总目录在000集 如何0元学微信小程序–【浅入深出系列000】 文章目录 本系列校训学习资源的选择先说总目录经常碰到的文件(目录&#xff09;最最常见的目录pages次最常用的就是images 目录 操作起来真正的操作 配套资源 本系列校训 用免费公开视频&#xff0c;卷…

Nginx问题汇总

为什么Nginx性能这么高&#xff1f; 主要是因为他的事件处理机制&#xff1a;异步非阻塞事件处理机制&#xff08;事件驱动的异步模型&#xff09;&#xff1a;运用了epoll模型&#xff0c;Nginx 会创建一些事件对象&#xff0c;然后将这些事件对象注册到事件驱动器中。当事件…

串口wifi6+蓝牙二合一系列模块选型参考和外围电路参考设计-WG236/WG237

针对物联网数据传输&#xff0c;智能控制等应用场景研发推出的高集成小尺寸串口WiFi串口蓝牙的二合一组合模块。WiFi符合802.11a/b/g/n无线标准&#xff0c;蓝牙支持低功耗蓝牙V4.2/V5.0 BLE/V2.1和EDR&#xff0c;WiFi部分的接口是UART&#xff0c;蓝牙部分是UART/PCM 接口。模…