线程池,以及线程池的实现以及面试常问的问题,工厂模式,常见的锁策略(面试常考,要了解,不行就背)

news2024/10/6 10:28:40

一、💛

线程池的基本介绍

内存池,进程池,连接池,常量池,这些池子概念上都是一样的~~

如果我们需要频繁的创建销毁线程,此时创建销毁的成本就不能忽视了,因此就可以使用线程池。

提前创建好一波线程,后续需要使用线程,就直接从池子里面拿一个即可,当线程不再使用,就放回池子里面。(本来是需要创建线程/销毁线程,现在是从池子里面获取到现成的线程,并且把线程归还到池子里面

那么为啥从池子里面拿就比系统里面创建线程更加高效呢?

不用线程池:如果是系统这里创建线程,需要调用系统API,进一步的由操作系统内核完成,完成线程的创建过程(内核是给所有进程提供服务的,这样你想干的事情,就需要等一等,等多长时间我们是未知的,是不可以控制的)

使用线程池:上述的内核中进行的操作都是提前做好了的,现在的取线程过程,纯粹的是用户使用代码完成的(纯用户态)-是可控制的。

二、💙

工厂模式:去生产的功能(字面意思),用于生产对象,一般情况下我们创建对象都是new,通过构造方法,但是构造方法有时候存在巨大的缺陷(构造方法是固定就是类名,有的类需要使用多种不同构造方式->(方法重载仅要求参数的个数和类型有区别)

~比如说:表示坐标->这种无法构成重载

public class Circle {
    public Circle(double x,double y){         //笛卡尔坐标
        
    };
    public  Circle(double r,double a){        //极坐标
         
    };
}
所以上面的代码也不对,构不成方法重载

使用工厂模式来解决上述问题,不使用构造方法来,(我刚开始也在想为什么是静态,直到我自己去试一下,明白了也就是说不用构造方法创建对象,假如不是静态方法,那么该怎么调用他呢,不是静态的,可是只能用对象.方法才可以调用)用普通方法来构造对象,这样方法就可以任意的了,普通方法内部去new对象~由于普通方法的目的是创建对象,然后调用方法来设置属性,所以方法一般都是静态的。(类名.方法)

三、💜 

//Executors:工厂类,后面的是工厂方法。这句话是创建一个固定线程数量的线程池
//线程池对象:ExecutorService service
        ExecutorService service= Executors.newFixedThreadPool(4);
//创建一个线程数组,动态变化的线程池。
        ExecutorService service2= Executors.newCachedThreadPool();
//包含单个线程(比原生创建API更简单一些指Thread)
        ExecutorService service3= Executors.newSingleThreadExecutor();
//类似于定时器效果,添加一些任务,执行,被执行的时候,不是只有有一个扫描线程来执行,可能是有多个共同执行
        ExecutorService service4= Executors.newScheduledThreadPool();
    }

 

四、❤️

面试题:谈谈java库中的线程池构成方法的参数和含义

这个方法最复杂,而且别的参数这个参数都有,所以就只解释这个方法就行。

int corePoolSize:核心线程数

int maximunPoolSize:最大线程数

ThreadPoolExcutor:里面的线程个数,并

非固定不变的,会根据当前任务的情况动态变化(自适应)

corePoolSize:至少要这些线程,哪怕你的线程都没任务也要这些个线程(如同公司里面的正式员工)

maximumPoolSize:最多不超过这些线程,哪怕干冒烟了,也不能比这个更多了(正式员工+实习生)

long keepAliveTime, TimeUnit unit:实习生线程,空闲时间超过指定阈值(允许实习生摸鱼的最大时间),就可以销毁了

BlockingQueue<Runnable>workQueue:线程池内部有很多很多,任务可以使用阻塞队列管理,线程池可以内置阻塞队列,也可以手动一个。

RejectedExecutionHandler   handler:线程池考的重点,拒绝方式/拒绝策略,线程池有一个阻塞队列,当队列满了,继续加任务如何处理。

1.ThreadPoolExecutors.AbortPolicy:直接抛出异常,线程池就不干活了,(小王喊我打球,我在学习,我直接崩溃了,我哇哇大哭)

2.ThreadPoolExecutor.callerRunsPolicy:谁说添加这个任务的线程,谁就去执行这个任务

,我会直接说:我没空,自己投去吧)

3.ThreadPoolExecutor.DiscardPolicy:把新的任务丢弃,(不打球了,我接着学习)

4.ThreadPoolExecutor.DiscardPolicy:丢弃最早的任务,执行新的任务(放弃学习,去打球)

有的线程公司会推荐使用这个。

 

五、💚 

具体实现一个线程池

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

class MyThreadPool {
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

//通过这个方法把任务添加到线程池中
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }


//n表示一个线程池里面有几个字段,创建了一个固定数量的线程池
    public MyThreadPool(int n) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                while (true) {
                    Runnable runnable = null;
                    try {
                        runnable = queue.take();      //从队列中提取这个任务
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    runnable.run();                  //运行这个任务
                }
            });
            t.start();                              //开启这个线程
        }
    }
}
public class Demo4 {

    public static void main(String[] args) throws InterruptedException {
        //获取当前引用实例
        MyThreadPool myThreadPool = new MyThreadPool(4);
        for (int i = 0; i < 1000; i++) {               //循环很关键哈,这个循环是添加1000次任务,但是假如你放到run里面,就会变成一个任务,至少内容是执行1000遍,线程是执行多个任务,但是不能一个任务还分担
            myThreadPool.submit(new Runnable() {           //(安排任务,安排一个任务)
                @Override                                  //这个任务进行的工作
                public void run() {

                    System.out.println(Thread.currentThread().getName() + " love");
                }
            });
        }
    }
}

面试问题2号:创建线程池的时候,线程个数怎么数的:

网路上查资料很多:假设cpu逻辑数是N,线程的个数:N,N+1,2N···

准确的说都不准确,因为不同的项目要做的工作是不同的:

cpu密集型线程工作:全是运算大部分工作在cpu上完成,cpu给他安排核心,才能概括,假如cpu N个核心,线程数量最好也是为N,如果多了,线程也只能是排队等待,没有新的进展

Io密集型线程工作:涉及大量等待时间,等待的过程,不要cpu,所以这里线程多,也会给cpu造成负担,cpu16核,整个32个线程,不犯毛病(不耗cpu,甚至cpu占用很低)———

实际上,一部分cpu密集,一部分Io密集,是我们工作中的常态,此时一个线程多少在cpu上执行,多少等待IO,说不好,更好的做法:自己去性能测试一下,找到性能和开销比较均衡的数值


六、💔 

多线程进阶开启:

常见的锁策略

如果工作中,真正要实现一把锁,需要理解锁策略

1.乐观锁VS悲观锁

乐观锁:预测,不太会出现锁冲突的情况

悲观锁:预测,这个场景非常容易锁冲突

2.重量级锁VS轻量级锁

重量级锁:加锁开销比较大,花的时间多,占有系统资源,一个悲观锁,很可能是重量级锁

轻量级锁:花的时间少,占有资源少,加锁的开销比较小的,很可能是乐观锁

悲观,乐观是加锁之前堆冲突概率的预测,决定工作的多少,重量,轻量,是加锁后,考虑实际的锁开销

3.自旋锁VS刮起等待锁

自旋锁是轻量级的一种典型实现,在用户态通过自旋的方式(while循环),实现类似加锁的操作(一直在疯狂的舔,这种锁会耗一定的cpu,但是是最快速度拿到锁的)

挂起等待锁:通过内核态,借助系统提供的锁机制,当出现锁冲突,会牵扯到内核对线程的调度,是冲突的线程出现挂起(阻塞等待)重量级锁的一种典型体现,发现锁被占用后,自己该干啥干啥,偶尔听到了消息,又去找这个锁,耗费cpu少,但无法第一时间拿到锁(小摆烂)

4.读写锁VS互斥锁

读写锁:把读操作,写操作分开了

假如两个线程 一个读加锁,另一个还是读加锁,那么两个不会有锁竞争(目的:就是把这种情况处理,这样多线程的效率会更高)

一个读,一个写,两个都是写都会有锁竞争,但是两个读没事,在开发中读操作会比写操作更加频繁

互斥锁:写了就不能读,读了就不可以写,

5.公平锁VS非公平锁

公平锁是遵循先来后到这个规则的

非公平锁相当于超市促销,都来抢位置,不遵守顺序

操作系统自带锁(pthread-mutex)是非公平锁,要实现公平锁,就需要一些额外的数据结构来支持(比如需要有办法记录每个线程的阻塞等待时间)

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

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

相关文章

数据结构刷题训练:设计循环队列(力扣OJ)

目录 文章目录 前言 1. 题目&#xff1a;设计循环队列 2. 思路 3. 分析 3.1 定义循环队列 3.2 创建队列 3.3 判空和判满 3.4 入队 3.5 出队 3.6 取队头队尾数据 3.7 销毁队列 4. 题解 总结 前言 当谈到队列数据结构时&#xff0c;很多人可能会想到普通的队列&#xff0c;即先进…

拷贝对象时的一些编译器优化

在传参和传返回值的过程中&#xff0c;一般编译器会做一些优化&#xff0c;减少对象的拷贝&#xff0c;这个在一些场景下还是非常有用的

Linux之awk判断和循环

echo zhaoy 70 72 74 76 74 72 >> score.txt echo wangl 70 81 84 82 90 88 >> score.txt echo qiane 60 62 64 66 65 62 >> score.txt echo sunw 80 83 84 85 84 85 >> score.txt echo lixi 96 80 90 95 89 87 >> score.txt把下边的内容写入到s…

FL Studio for Windows-21.1.0.3713中文直装版功能介绍及系统配置要求

FL Studio 21简称FL水果软件,全称是&#xff1a;Fruity Loops Studio编曲&#xff0c;由于其Logo长的比较像一款水果因此&#xff0c;在大家更多的是喜欢称他为水果萝卜&#xff0c;FL studio21是目前最新的版本&#xff0c;这是一款可以让你的计算机就像是一个全功能的录音室&…

SpringBoot复习(39)Servlet容器的自动配置原理

Servlet容器自动配置类为ServletWebServerFactoryAutoConfiguration 可以看到通过Import注解导入了三个配置类&#xff1a; 通过这个这三个配置类可以看出&#xff0c;它们都使用了ConditionalOnClass注解&#xff0c;当类路径存在tomcat相关的类时&#xff0c;会配置一个T…

matlab解常微分方程常用数值解法2:龙格库塔方法

总结和记录一下matlab求解常微分方程常用的数值解法&#xff0c;本文将介绍龙格库塔方法&#xff08;Runge-Kutta Method&#xff09;。 龙格库塔迭代的基本思想是&#xff1a; x k 1 x k a k 1 b k 2 x_{k1}x_{k}a k_{1}b k_{2} xk1​xk​ak1​bk2​ k 1 h f ( x k , t …

ZDH-wemock模块

本次介绍基于版本v5.1.1 目录 项目源码 预览地址 安装包下载地址 wemock模块 wemock模块前端 配置首页 配置mock wemock服务 下载地址 打包 运行 效果展示 项目源码 zdh_web: https://github.com/zhaoyachao/zdh_web zdh_mock: https://github.com/zhaoyachao/z…

带你了解接收参数@PathVariable、@ModelAttribute 等相关注解

&#x1f600;前言 本篇博文是关于SpringBoot 接收客户端提交数据/参数会使用到的相关注解应用说明&#xff0c;希望能够帮助到您&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文…

elasticsearch 基础

ES 搜索技术历史 今天看的是《Elasticsearch实战与原理解析》 第一章 搜索技术发展史 1、搜索技术发展史 宏观而言&#xff0c;搜索引擎的发展经历了五个尖端和两大分类。五个阶段分别是ftp文件检索阶段、分类目录阶段、文本相关性检索阶段、网页链接分析阶段和用户意图识别…

警惕 C++ 中的隐式类型转换

今天文章的主题灵感来自客户的一个问题&#xff1a; 我在研究一个代码中的栈溢出问题。为了减小栈帧的大小&#xff0c;我尽可能多地删除了局部变量&#xff0c;但仍有很多栈空间无法解释。除了局部变量、参数、保存的寄存器和返回地址之外&#xff0c;栈上还有什么其他的东西…

第八章 CUDA内存应用与性能优化篇(上篇)

cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…

机器学习线性代数基础

本文是斯坦福大学CS 229机器学习课程的基础材料&#xff0c;原始文件下载 原文作者&#xff1a;Zico Kolter&#xff0c;修改&#xff1a;Chuong Do&#xff0c; Tengyu Ma 翻译&#xff1a;黄海广 备注&#xff1a;请关注github的更新&#xff0c;线性代数和概率论已经更新完毕…

ACL 2023 | 使用语言模型解决数学推理问题的协同推理框架

©PaperWeekly 原创 作者 | 朱欣宇 单位 | 清华大学 研究方向 | 自然语言处理 论文标题&#xff1a; Solving Math Word Problems via Cooperative Reasoning induced Language Models 论文链接&#xff1a; https://arxiv.org/abs/2210.16257 代码链接&#xff1a; https…

2023 互联网大厂薪资大比拼

最近整理了33家互联网大厂的薪资情况。可以看出来&#xff0c;大部分互联网大厂薪资还是很不错的&#xff0c;腾讯、阿里、美团、百度等大厂平均月薪超过30k&#xff0c;其他互联网大厂平均月薪也都在25k以上。01020304050607080910111213141516171819202122232425262728293031…

ESP8266(RTOS SDK)内嵌网页以实现WEB配网以及数据交互

【本文发布于https://blog.csdn.net/Stack_/article/details/131997098&#xff0c;未经允许不得转载&#xff0c;转载须注明出处】 1、执行make menuconfig&#xff0c;将http头由512改为更大的值&#xff0c;否则用电脑浏览器访问正常&#xff0c;但用手机浏览器访问会因为ht…

关于`IRIS/Caché`进程内存溢出解决方案

文章目录 关于IRIS/Cach进程内存溢出解决方案 描述原因相关系统变量$ZSTORAGE$STORAGE 什么情况下进程内存会变化&#xff1f;内存不足原理解决方案 关于 IRIS/Cach进程内存溢出解决方案 描述 在IRIS/Cach中&#xff0c;进程内存溢出错误是指一个进程&#xff08;例如运行中的…

群晖 nas 自建 ntfy 通知服务(梦寐以求)

目录 一、什么是 ntfy ? 二、在群晖nas上部署ntfy 1. 在Docker中安装ntfy 2. 设置ntfy工作文件夹 3. 启动部署在 docker 中的 ntfy&#xff08;binwiederhier/ntfy&#xff09; 三、启动配置好后&#xff0c;如何使用ntfy 1. 添加订阅主题&#xff08; Subscribe to topic…

六种不同的CRM系统类型分别有哪些特点?

企业想要管理销售&#xff0c;可以选择CRM系统&#xff1b;企业想要优化业务流程&#xff0c;可以选择CRM系统&#xff1b;企业想要提高收入&#xff0c;可以选择CRM系统。下面来说说&#xff0c;CRM是什么&#xff1f;六种常见CRM系统类型对比。 什么是CRM&#xff1f; CRM是…

当执行汇编指令MOV [0001H] 01H时,CPU都做了什么?

今天和几位单位大佬聊天时&#xff0c;讨论到一个非常有趣的问题-当程序执行MOV [0001H], 01H计算机实际上都做了哪些工作&#xff1f;乍一看这个问题平平无奇&#xff0c;CPU只是把立即数01H放在了地址为0001的内存里&#xff0c;但仔细想想这个问题远没有那么简单&#xff0c…