设计模式(单例模式,工厂模式),线程池

目录

什么是设计模式?

单例模式

饿汉模式

懒汉模式

工厂模式

线程池

线程池种类

ThreadPoolExcutor的构造方法:

手动实现一个线程池 


什么是设计模式?

计算机行业程序员水平层次不齐,为了让所有人都能够写出规范的代码,于是就有了设计模式,针对一些典型的场景,给出一些典型的解决方案

单例模式

单例模式 ==> 单个实例(对象)

在一些场景中,有的特定类只能创建一个实例,不能创建多个实例
使用了单例模式后,此时就不能创建多个实例了,我们想创建多个实例都难,单例模式就是针对上述的需求场景进行了更强制的保证,通过巧用java的语法,达成某个类 只能被创建出一个实例这样的效果(当程序员不小心创建了多个实例,就会报错)

单例模式实现

饿汉模式

// 饿汉模式的 单例模式 实现
// 此处保证 Singleton 这个类只能创建出一个实例
class Singleton{// 在此处,先把实例给创建出来private static Singleton instance = new Singleton();// 如果需要使用 instance,通过统一的Singleton.getInstance() 方式获取public static Singleton getInstance(){return instance;}// 为了避免 Singleton 类不小心被复制多份// 把构造方法设为 private,在类外面,就无法通过new 的方式来创建这个 Singleton了private Singleton(){};
}
public class Thread3 {public static void main(String[] args) {Singleton s = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s==s2);Singleton s3 = new Singleton(); // 报错,原因是Singleton的构造方法被private修饰,因此无法通过new的方式创建Singleton对象}
}

懒汉模式

class Singleton2{ private static volatile Singleton2 instance = null; //使用volatile表示instance是个易变的public static Singleton2 getInstance(){if (instance==null) {   // 此处负责判断是否要加锁synchronized (Singleton2.class) {if(instance==null){   // 此处判断是否要创建对象instance = new Singleton2();}}}return instance;}private Singleton2(){};
}

懒汉模式下,有创建Singleton对象的操作(写操作),所以可能会出现线程安全问题,因此我们要进行加锁操作,并标注instance是一个易变的对象(避免内存可见性问题,和指令重排序问题)

工厂模式

工厂模式: 使用普通的方法,来代替构造方法,创建对象.  在java中,构造方法存在一定缺陷,构造方法要求构造名必须为类名(方法名相同),构造参数可以不同,没用返回值.如果我们只构造一种对象可以忽略这个缺陷,如果构造多种不同的情况的对象可能会出现问题,比如想要实现俩个不同的构造方法,但是它们的参数类型恰好都相同,但表达的意义不同,这时java就无法区分了.为了解决这个问题,就可以使用工程模式

比如分别使用笛卡尔坐标系和极坐标系表示坐标

import java.awt.*;
class PointFactory{public static Point makePointByXY(double x,double y){}public static Point makePointByRA(double r,double a){}
}
public class Thread6 {public static void main(String[] args) {Point p = PointFactory.makePointByXY(10,20);Point p2 = PointFactory.makePointByRA(10,30);}
}

线程池

线程存在的意义: 使用进程实现并发编程,"太重了",引入线程(轻量级进程),创建线程比创建线程更高效,销毁线程比销毁进程更高效,调度线程比调度进程更高效,此时使用多线程就可以在很多时候代替进程实现并发编程了

线程池存在的意义: 当我们需要频繁创建销毁线程的时候,就发现开销也很大,想要进一步的提高效率,可以: 1.搞一个协程(轻量级线程) 2.使用线程池,事先把需要使用的线程创建好,放到池中,后面需要使用的时候,从池中获取,如果用完了,再还给池.(创建线程和销毁线程是交由操作系统内核去完成的,从池子里获取/还给池,是自己用户代码就能实现的,不必交给内核操作)

public class Thread5 {public static void main(String[] args) {// 此处就构造了一个 10 个线程的线程池,就可以随时安排这些线程干活了ExecutorService pool =  Executors.newFixedThreadPool(10);// 当前往线程池中放了1000个任务,这1000个任务由线程池中的10个线程去执行for (int i = 0;i < 1000;i++) {pool.submit(()->{System.out.println("hello");});}}
}

线程池提供了一个重要的方法,submit,可以给线程池提交若干个任务,这若干个任务可以由线程池中的线程去执行完成..线程池中创建的线程是前台线程,需要执行完成后,主线程才可以结束. 
这里1000个任务相当于在一个队列中,线程池中的这10个线程就依次取这个队列中的任务,取一个就执行一个,执行完成后,再在这个队列中取任务去执行 

线程池种类

这些线程池,本质上都是通过包装 ThreadPoolExecutor 来实现的 

ThreadPoolExcutor的构造方法:

corePoolSize : 核心线程数,

maximumPoolSize:  最大线程数,相当于线程池把线程分为俩大类,一类是核心线程,一类是非核心线程,最大线程数就是核心线程和非核心线程之和
一个程序有时任务多,有时任务少,如果任务多,我们就需要多一些线程,如果任务少,就需要线程尽量少,此时我们就可以保留核心线程,而淘汰掉一些非核心线程

实际开发中,线程池的线程数设定成多少合适?

程序分为CPU密集型,每个线程执行的任务都需要狂转CPU(进行一系列算术运算),此时线程池线程数最多不超过CPU核数,因为cpu密集型要一直占用cpu,创建更多的线程也没用
IO密集型,每个线程的工作就是等待IO(读写硬盘,读写网卡,等待用户输入),不占CPU,此时这样的线程处于阻塞状态,不参与CPU调度,这个时候创建多个线程,不再受制于CPU核数了
实践中确定线程数,通过实验的方式,康康设置几个线程合适

long keepAliveTime: 非核心线程数不工作的最大时间,如果超过这个时间就销毁

TimeUnit unit: 时间单位,ms,s,分钟,小时......

BlockingQueue<Runnable> workQueue: 线程池的任务队列

ThreadFactory threadFactory: 用于创建线程

RejectedExecutionHandler handler: 描述了线程池的"拒绝策略",是一个特殊的对象,描述了当线程池任务队列满了之后,如果继续添加任务,线程池会有什么样的行为,总共有以下4种策略
ThreadPoolExcutor.AbortPolicy: 如果任务队列满了,再新增任务,直接抛出异常
ThreadPoolExcutor.CallerRunsPoliy: 如果任务队列满了,多出来的任务,谁加的就由谁去执行(交给调用者去执行)
ThreadPoolExcutor.DisardOlderdestPolicy: 如果任务队列满了,就丢弃最老的任务
ThreadPoolExcutor.DiscardPolicy: 如果任务队列满了,就丢弃最新的任务

手动实现一个线程池 

一个线程池中至少有俩个部分,一个是阻塞队列,用来保存任务,一个是若干个工作线程

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();}}
}

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

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

相关文章

java+springboot+mysql村务档案管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的村务档案管理系统&#xff0c;系统包含超级管理员、工作人员角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;系统用户管理&#xff08;工作人员管理&#xff09;&#xff1b;公开资料&#xff1b;会议记录&…

A Survey on Knowledge-Enhanced Pre-trained Language Models

摘要 自然语言处理(NLP)已经通过使用BERT等预训练语言模型(plm)发生了革命性的变化。尽管几乎在每个NLP任务中都创造了新的记录,但plm仍然面临许多挑战,包括可解释性差,推理能力弱,以及在应用于下游任务时需要大量昂贵的注释数据。通过将外部知识集成到plm中,知识增强预训…

.NET 最便捷的Log4Net日志记录器

最便捷的Log4Net使用方法 LOG4NET 配置日志记录器开始引用nuget LOG4NET 配置日志记录器 Apache log4net 库是一个帮助程序员将日志语句输出到各种的工具 的输出目标。log4net是优秀的Apachelog4j™框架的移植 Microsoft.NET 运行时。我们保持了与原始log4j相似的框架 同时利…

Rust处理JSON

基本操作 Cargo.toml: [package]name "json"version "0.1.0"edition "2021"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]serde { version "1", features …

前端(十四)——DOM节点操作手册:你需要了解的一切

&#x1f642;博主&#xff1a;小猫娃来啦 &#x1f642;文章核心&#xff1a;DOM节点操作手册&#xff1a;你需要了解的一切 文章目录 前言DOM基础知识操作现有节点创建新节点遍历节点树修改节点属性和样式事件处理实践应用动态创建表格动态更新列表 前言 DOM&#xff08;文档…

算法岗和开发岗有什么区别?

算法岗和开发岗有什么区别&#xff1f; ​ 算法岗位和开发岗位在实际应用中有很大的差异&#xff0c;而且其工作的内容重心也不一样。企业对职位能力的要求也是存在着很大的区别。 ​ 其实在真正的实践中&#xff0c;只有大厂才对这两个岗位分的比较清楚&#xff0c;小的公司…

计算机网络第3章(数据链路层)

计算机网络第3章&#xff08;数据链路层&#xff09; 3.1 数据链路层概述3.1.1 概述3.1.2 数据链路层使用的信道3.1.3 三个重要问题 3.2 封装成帧3.2.1 介绍3.2.2 透明传输3.2.3 总结 3.3 差错检测3.3.1 介绍3.3.2 奇偶校验3.3.3 循环冗余校验CRC(Cyclic Redundancy Check)3.3.…

【FAQ】安防监控视频汇聚平台EasyCVR接入GB国标设备,无法显示通道信息的排查方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

【分析绘图】R语言实现一些常见的绘图

微生信-在线绘图网站 线性图 library(ggplot2)x <- rnorm(100, 14, 5) # rnorm(n, mean 0, sd 1) y <- x rnorm(100, 0, 1) ggplot(data NULL, aes(x x, y y)) # 开始绘图geom_point(color "darkred") # 添加点annotate("text",x 13,…

【从零学习python 】92.使用Python的requests库发送HTTP请求和处理响应

文章目录 URL参数传递方式一&#xff1a;使用字典传递参数URL参数传递方式二&#xff1a;直接在URL中拼接参数获取响应头信息获取响应体数据a. 获取二进制数据b. 获取字符数据c. 获取JSON数据 进阶案例 URL参数传递方式一&#xff1a;使用字典传递参数 url https://www.apiop…

idea使用tomcat

1. 建立javaweb项目 2. /WEB-INF/web.xml项目配置文件 如果javaweb项目 先建立项目&#xff0c;然后在项目上添加框架支持&#xff0c;选择javaee 3. 项目结构 4.执行测试&#xff1a;

系统稳定性与高可用保障

一、前言 高并发、高可用、高性能被称为互联网三高架构&#xff0c;这三者都是工程师和架构师在系统架构设计中必须考虑的因素之一。今天我们就来聊一聊三 H 中的高可用&#xff0c;也是我们常说的系统稳定性。 > 本篇文章只聊思路&#xff0c;没有太多的深入细节。阅读全…

新手如何快速学习C++!思路清晰好执行

C是一种广泛使用的编程语言&#xff0c;它被广泛应用于游戏开发、系统编程、嵌入式开发等领域。对于新手来说&#xff0c;快速掌握C技能是非常重要的。本文将为新手提供一些快速学习C的方法和技巧。 1.了解C的基本语法 学习C的第一步是了解其基本语法。C的语法非常严谨和规范…

Springboot实现ENC加密

Springboot实现ENC加密 1、导入依赖2、配置加密秘钥&#xff08;盐&#xff09;3、获取并配置密文4、重启项目测试5、自定义前缀、后缀6、自定义加密方式 1、导入依赖 关于版本&#xff0c;需要根据spring-boot版本&#xff0c;自行修改 <dependency><groupId>co…

Python可视化工具库实战

Matplotlib Matplotlib 是 Python 的可视化基础库&#xff0c;作图风格和 MATLAB 类似&#xff0c;所以称为 Matplotlib。一般学习 Python 数据可视化&#xff0c;都会从 Matplotlib 入手&#xff0c;然后再学习其他的 Python 可视化库。 Seaborn Seaborn 是一个基于 Matplo…

● 647. 回文子串 ● 516.最长回文子序列

647. 回文子串 class Solution { public:int countSubstrings(string s) {vector<vector<bool>>dp(s.size(),vector<bool>(s.size(),false));int res0;for(int is.size()-1;i>0;i--){for(int ji;j<s.size();j){if(s[i]s[j]){if(j-i<1){res;dp[i][…

微服务 Nacos配置热部署

在nacos中添加配置文件 在配置列表中添加配置&#xff0c; 注意&#xff1a;项目的核心配置&#xff0c;需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 从微服务拉取配置 微服务要拉取nacos中管理的配置&#xff0c;并且与…

大厂考核重点:mysql索引面试题

很多同学面对Mysql索引相关的面试题都是死记硬背的&#xff0c;这肯定是不行的&#xff0c;也不容易记住&#xff0c;所以大家还是要循循渐进&#xff0c;从理解开始&#xff0c;慢慢掌握&#xff0c;当然对于想要准备面试题的同学&#xff0c;这几个问题是需要记住并理解的&am…

数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成

数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成 目录 数据生成 | MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成生成效果基本描述模型描述程序设计参考资料 生成效果 基本描述 1.MATLAB实现MCMC马尔科夫蒙特卡洛模拟的数据生成&#xff1b; 2.马尔科夫链蒙特卡洛方…

服务器数据恢复-ESXi虚拟化误删除的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器安装的ESXi虚拟化系统&#xff0c;该虚拟化系统连接了多个LUN&#xff0c;其中一个LUN上运行了数台虚拟机&#xff0c;虚拟机安装Windows Server操作系统。 服务器故障&分析&#xff1a; 管理员因误操作删除了一台虚拟机&#x…