多线程(安全 同步 线程池)

线程安全问题

  • 多线程给我们的程序带来了很大性能上的提升,但是也可能引发线程安全问题
  • 线程安全问题指的是当多个线程同时操作同一个共享资源的时候,可能会出现的操作结果不符预期问题

取钱的线程安全问题

image-20240414145604621
  • 线程安全问题出现的原因?

    • 存在多线程并发
    • 同时访问共享资源
    • 存在修改共享资源
  • 线程安全问题发生的原因是什么?

    • 多个线程同时访问同一个共享资源且存在修改该资源。

线程同步方案

认识线程同步

思想

  • 线程同步就是让多个线程实现先后依次访问共享资源,这样就解决了安全问题,它最常见的方案就是加锁
  • **加锁:**每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来。

同步代码块(方式一)

作用: 把访问共享资源的核心代码给上锁,以此保证线程安全。

synchronized(同步锁) { 访问共享资源的核心代码 }

同步锁的注意事项

  • 对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug
  • 对于实例方法建议使用this作为锁对象
  • 对于静态方法建议使用字节码(类名.class)对象作为锁对象

同步方法(方式二)

Lock锁(方式三)

Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。

Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。

构造器说明
public ReentrantLock()获得Lock锁的实现类对象

方法

方法名称说明
void lock()获得锁
void unlock()释放锁

总结(三种方式对比)

同步代码块同步方法lock
语法synchronized (this){ }synchronized 方法(){ }lock.lock(); lock.unlock();
加锁方式自动加锁、释放锁自动加锁、释放锁手动加锁、释放锁
锁粒度代码行方法代码行

线程池(重点)

认识线程池

当前创建线程的问题

  • 用户每发起一个请求,后台就需要创建一个新线程来处理,任务处理完毕之后,线程就会被销毁
  • 下次新任务来了肯定又要创建新线程处理的,用完又要被销毁
  • 而创建和销毁线程的开销是很大的,当请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能

什么是线程池?

  • 线程池就是一个可以复用线程的技术
  • 它就像一个大的池子一样,里面可以放置一些线程,当需要的时候,就从里面取出来用,用完了就还回去
  • 如此一来,就不必频繁的创建和销毁线程了,大大的提高了线程的利用率,提供系统的性能

不使用线程池的问题

  • 如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。
工作原理
image-20230508143331334

线程池的执行流程

image-20240414151501222
  • 判断核心线程数是否已满,如果没满,则创建一个新的核心线程来执行任务
  • 如果核心线程满了,则判断工作队列是否已满,如果没满,则将任务存储在这个工作队列
  • 如果工作队列满了,则判断最大线程数是否已满,如果没满,则创建临时线程执行任务
  • 如果最大线程数已满,则执行拒绝策略

如何创建线程池

谁代表线程池

JDK 5.0起提供了代表线程池的接口:ExecutorService。

如何得到线程池对象?

使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。

public ThreadPoolExecutor( int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler) 参数一:corePoolSize : 指定线程池的核心线程的数量     正式工: 3  (不能小于0)                   
参数二:maximumPoolSize:指定线程池的最大线程数量	最大员工数: 5	临时工: 2  (最大数量>=核心线程数量)
参数三:keepAliveTime :指定临时线程的存活时间	(不能小于0) 	
参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)	临时工空闲多久被开除   (时间单位)
参数五:workQueue:指定线程池的任务队列		客人排队的地方		(null)
参数六:threadFactory:指定线程池的线程工厂	负责招聘员工的 	(null)
参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)	忙不过来怎么办    	(null)

线程池如何处理Runnable任务

  • 使用ExecutorService的方法:
  • void execute(Runnable target)

线程池如何处理Callable任务,并得到任务执行完后返回的结果。

  • 使用ExecutorService的方法:
  • Future submit(Callable command)

Executors工具类底层是基于什么方式实现的线程池对象?

  • 线程池ExecutorService的实现类:ThreadPoolExecutor

Executors是否适合做大型互联网场景的线程池方案?

  • 不合适。
  • 建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。
任务缓冲队列
队列详解
ArrayBlockingQueue基于数组的有界缓存等待队列,可以指定缓存队列的大小
LinkedBlockingQueue基于链表的无界阻塞队列,此时最大线程数无效
任务拒绝策略
策略详解
ThreadPoolExecutor.AbortPolicy丢弃任务并抛出RejectedExecutionException异常。是默认的策略
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常 这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy抛弃队列中等待最久的任务 然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunsPolicy由主线程负责调用任务的run()方法从而绕过线程池直接执行

线程池处理Runnable任务

ExecutorService的常用方法

方法名称说明
void execute(Runnable command)执行 Runnable 任务
Future submit(Callable task)执行 Callable 任务,返回未来任务对象,用于获取线程返回的结果
void shutdown()等全部任务执行完毕后,再关闭线程池!
List shutdownNow()立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的任务

线程池如何处理Runnable任务

使用ExecutorService的方法:void execute(Runnable target)

线程池处理Callable任务

ExecutorService的常用方法

方法名称说明
void execute(Runnable command)执行任务/命令,没有返回值,一般用来执行 Runnable 任务
Future submit(Callable task)执行任务,返回未来任务对象获取线程结果,一般拿来执行 Callable 任务
void shutdown()等任务执行完毕后关闭线程池
List shutdownNow()立刻关闭,停止正在执行的任务,并返回队列中未执行的任务

线程池如何处理Callable任务,并得到任务执行完后返回的结果?

使用ExecutorService的方法:Future<T> submit(Callable<T> command)

Executors工具类实现线程池

Executors

  • **是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。 **
方法名称说明
public static ExecutorService newFixedThreadPool(int nThreads)创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorService newSingleThreadExecutor()创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
public static ExecutorService newCachedThreadPool()线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60s则会被回收掉。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。

注意 :这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。

Executors使用可能存在的陷阱

  • 大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
image-20240414155609462

总结

  1. Executors工具类底层是基于什么方式实现的线程池对象?
    • 线程池ExecutorService的实现类:ThreadPoolExecutor
  2. Executors是否适合做大型互联网场景的线程池方案?
    • 不合适。
    • 建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。

线程通信(了解)

**什么是线程通信? **

当多个线程共同操作共享的资源时,线程间通过某种方式互相告知自己的状态,以相互协调,并避免无效的资源争夺。

线程通信的常见模型(生产者与消费者模型)

  • 生产者线程负责生产数据
  • 消费者线程负责消费生产者生产的数据。
  • 注意:生产者生产完数据应该等待自己,通知消费者消费;消费者消费完数据也应该等待自己,再通知生产者生产!

线程通信的三个常见方法

方法名称说明
void wait()当前线程等待,直到另一个线程调用notify() 或 notifyAll()唤醒自己
void notify()唤醒正在等待对象监视器(锁对象)的单个线程
void notifyAll()唤醒正在等待对象监视器(锁对象)的所有线程
  • 注意
    • 上述方法应该使用当前同步锁对象进行调用。

理论补充

进程与线程

  • 进程:正在运行的程序(软件)就是一个独立的进程
  • 线程:线程是属于进程的,一个进程中可以同时运行很多个线程
  • 关系:进程=火车 线程=车厢

并发与并行

并发的含义

  • 进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,
  • CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发
image-20240414164954008

并行的含义

在同一个时刻上,同时有多个线程在被CPU调度执行。

image-20240414165008969

多线程到底是如何执行的?

并发与并行同时进行的

线程生命周期

也就是线程从生到死的过程中,经历的各种状态及状态转换,Java总共定义了6种状态

public class Thread{ ...  public enum State {NEW, 线程刚被创建,但是并未启动RUNNABLE, 线程已经调用了start(),等待CPU调度BLOCKED, 线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态WAITING, 一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒TIMED_WAITING, 同waiting状态,有几个方法(sleep,wait)有超时参数,调用他们将进入Timed Waiting状态TERMINATED; 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡}...
}

线程的6种状态互相转换

image-20240414165412488

补充知识:定时器

image-20230508143918532

image-20230508143951106

补充知识:并发、并行

image-20230508144102238

  • 简单说说并发和并行的含义
    • 并发:CPU分时轮询的执行线程。
    • 并行:同一个时刻同时在执行。

线程的生命周期(背诵)

image-20230508144234153

线程的6种状态总结

NEW(新建)线程刚被创建,但是并未启动。
Runnable(可运行)线程已经调用了start()等待CPU调度
Blocked(锁阻塞)线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态;。
Waiting(无限等待)一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒
Timed Waiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。带有超时参数的常用方法有Thread.sleep 、Object.wait。
Teminated(被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

image-20230508144423987

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

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

相关文章

创新科技赋能旅游服务:智慧文旅引领旅游发展新篇章,智能体验助力产业转型升级

随着科技的飞速发展和人们生活水平的提高&#xff0c;旅游业正迎来前所未有的发展机遇。创新科技在旅游服务领域的广泛应用&#xff0c;不仅提升了旅游体验的品质&#xff0c;也为旅游产业的转型升级注入了新的动力。智慧文旅作为旅游业与信息技术深度融合的产物&#xff0c;正…

matlab新手快速上手5(蚁群算法)

本文根据一个较为简单的蚁群算法框架详细分析蚁群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 蚁群算法简介&#xff1a; 蚁群算法是一种启发式优化算法&#xff0c;灵感来源于观察蚂蚁寻找食物的行为。在这个算法中&#xff0c;解决方案被看作是…

如何利用交易形态的失败进行现货黄金?

进行现货黄金理财&#xff0c;除了需要投资者对黄金投资有热情之外&#xff0c;有方法也是很重要的&#xff0c;光有热情而没有技术&#xff0c;我们的资金很可能会成为其他人的囊中之物。但如果有了现货黄金理财的技术&#xff0c;情况就可能扭转过来。下面我们就从买入的角度…

vue2实现字节流byte[]数组的图片预览

项目使用vantui框架&#xff0c;后端返回图片的字节流byte[]数组&#xff0c;在移动端实现预览&#xff0c;实现代码如下&#xff1a; <template><!-- 附件预览 --><div class"file-preview-wrap"><van-overlay :show"show"><…

【draw.io的使用心得介绍】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

14.MMD导入Blender及贴图步骤

MMD导出.abc文件 在MMD十周年桥版本导入一个人物模型&#xff0c;这里导入仆人 注意MMD的路径不能有中文 点击上面的MMDBridge 设定 第一个选择blender by 第二个选择实行 这里是选择帧数范围和帧率 帧率一定要是30&#xff0c;不然后面可能会出问题 点击文件导出视频…

机器学习 -- 分类问题

场景 探讨了一个回归任务——预测住房价格&#xff0c;用到了线性回归、决策树以及随机森林等各种算法。本次中我们将把注意力转向分类系统。我们曾经对MNIST进行了分类任务&#xff0c;这次我们重新回到这里&#xff0c;细致的再来一次。 开始 获取数据 Scikit-Learn提供了…

说说2024年暑期三下乡社会实践工作新闻投稿经验

作为一名在校大学生,我有幸自去年起参与学院组织的暑期大学生三下乡社会实践团活动。这项活动不仅是我们深入基层、服务社会的重要平台,也是展现当代大学生风采、传递青春正能量的有效途径。然而,如何将这些生动鲜活的实践故事、感人至深的瞬间传播出去,让更多人了解并受到启发…

抽象的代理模式1.0版本

前言&#xff1a; 在阅读Spring Security官方文档时&#xff0c;里面设计到了一种设计模式——代理模式Proxy 众里寻她千百度&#xff0c;蓦然回首&#xff0c;那人却在灯火阑珊处 开始 在之前的文章里陈述了一个观点——编程语言和语言没有区别 现看看我们日常生活中的代理…

数据结构篇其一---顺序表

前言 数据结构篇&#xff0d;&#xff0d;&#xff0d;C语言实现数据结构 &#xff23;语言的基础知识&#xff1a;数组 函数 结构体 指针 动态内存分配。 顺序表 从数据结构的角度看待数组 int arr[10]; 数组是一个基本的数据结构吗&#xff1f; 这里以一维数组为例。 …

OpenCV 实现霍夫圆变换

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV实现霍夫变换 下一篇:OpenCV 实现重新映射 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 HoughCircles()检测图像中的圆圈。 理论 Hough 圆变换 H…

L2-052 吉利矩阵

题目描述 题解思路 这个道题就是很简单&#xff0c;就跟n皇后问题一样&#xff0c;给矩阵填数&#xff0c;使得矩阵满足一个什么条件&#xff0c;最后求方案数或者方案。很容易想到回溯法&#xff0c;根据数据范围&#xff0c;应该能够确定回溯法是没有问题的。 我们只需要枚举…

Python实现线性拟合及绘图

Python实现线性拟合及绘图 当时的数字地形实验&#xff0c;使用matplotlib库绘制了一张图表表示不同地形类别在不同分辨率下的RMSE值&#xff0c;并分别拟合了一条趋势线。现在来看不足就是地形较多时&#xff0c;需要使用循环更好一点&#xff0c;不然太冗余了。 代码逻辑 …

80个在线小游戏源码

源码简介 搭建80个在线小游戏网站源码&#xff0c;解压即可食用&#xff0c;支持在本地浏览器打开。 安装教程 纯HTML&#xff0c;直接将压缩包上传网站目录解压即可 首页截图 源码下载 80个在线小游戏源码-小8源码屋

vscode 打代码光标特效

vscode 打代码光标特效 在设置里面找到settings 进入之后在代码最下方加入此代码 "explorer.confirmDelete": false,"powermode.enabled": true, //启动"powermode.presets": "fireworks", // 火花效果// particles、 simple-rift、e…

STM32_舵机的实战

一、配置相应的管脚 二、写代码

ASP.NET集成客户关系管理的企业网站的设计与开发

摘 要 企业要在激烈的市场竞争中立于不败之地&#xff0c;就必须找一种全新的管理理念和管理手段&#xff0c;对其内部和外部资源进行有效的整合。新一代ERP产品正在向客户端和供应端延伸&#xff0c;客户端的延伸即是客户关系管理。对于每个企业来说客户管理的完善程度将直接…

大语言模型(LLM)漏洞爆发,AI模型无一幸免

本文概述了人工智能初创公司Anthropic于2024年04月03日发表的一篇针对人工智能安全的论文&#xff0c;该公司在本论文中宣布的一种新的“越狱”技术&#xff0c;名为Many-shot Jailbreaking&#xff08;多轮越狱&#xff09;。文章详细描述了目前大语言模型&#xff08;LLM&…

IOS恢复

1、实验目的 通过本实验可以掌握&#xff1a; copy方式恢复IOS的步骤。TFTPDNLD方式恢复IOS的步骤。Xmodem方式恢复IOS的步骤。 2、实验拓扑 路由器IOS恢复的实验拓扑如下图所示。 3、实验步骤 如果工作中不慎误删除路由器IOS&#xff0c;或者升级了错误版本的IOS&#xff…

目标检测网络YOLO进化之旅

yolo系列网络在目标检测领域取得了巨大的成功&#xff0c; 尤其是在工程实践中&#xff0c; 以其出色的性能优势获得了广泛的应用落地。 YOLO的前3个版本是由同一个作者团队出品&#xff0c; 算是官方版本。 之后的版本都是各个研究团队自己改进的版本&#xff0c; 之间并无明…