多线程
什么是进程? 什么是线程?
进程
进程是指在系统中正在运行的一个应用程序,程序一旦运行就是进程。进程是系统进行资源分配的独立实体, 且每个进程拥有独立的地址空间。一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。
进程之间的通信
进程间通信 IPC(管道,信号量,共享内存,消息队列)
线程
线程是进程的一个实体,是进程的一条执行路径。线程是CPU独立运行和独立调度的基本单位。
线程之间的通信
线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
进程与线程的选择取决以下几点:
1.需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的。
2.线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
3.因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程;
4.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求;
5.需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。
1.多线程
多线程是指从软件或者硬件上实现多个线程的并发技术
多线程的好处:
1.使用多线程可以把程序中占据时间长的任务放到后台去处理,如图片、视屏的下载
2.发挥多核处理器的优势,并发执行让系统运行的更快、更流畅,用户体验更好
多线程的缺点:
1.大量的线程降低代码的可读性;
2.更多的线程需要更多的内存空间
3.当多个线程对同一个资源出现争夺时候要注意线程安全的问题
2.多线程的创建方式
方式一:继承Thread类
重写Thread类的run()方法
创建Thread子类的对象
通过此对象调用start()方法
start与run方法的区别:
start方法的作用:1.启动当前线程 2.调用当前线程的重写的run方法(在主线程中生成子线程,有两条线程)
调用start方法以后,一条路径代表一个线程,同时执行两线程时,因为时间片的轮换,所以执行过程随机分配,且一个线程对象只能调用一次start方法。
run方法的作用:在主线程中调用以后,直接在主线程一条线程中执行了该线程中run的方法。(调用线程中的run方法,只调用run方法,并不新开线程)
总结:我们不能通过run方法来新开一个线程,只能调用线程中重写的run方法(可以在线程中不断的调用run方法,但是不能开启子线程,即不能同时干几件事),start是开启线程,再调用方法(即默认开启一次线程,调用一次run方法,可以同时执行几件事)
方式二:实现Runnable接口
开发中优先选择Runnable接口
1.创建一个实现了Runable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()
3.静态代理模式
1.真实对象和代理对象都要实现同一个接口
2.代理对象要代理真实的对象
好处:
代理对象可以做很多真实对象做不了的事情
真实对象可以专注做自己的事情
4.lambda
语法:
函数式接口 对象名=new Thread(()->{});
lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么要用代码块包裹
前提是接口为函数式接口
多个参数也可以去掉参数类型,要去掉都去掉,必须加上括号
5.线程的常用方法
1.线程停止
建议线程正常停止-->利用次数,不建议死循环
建议使用标志位-->设置一个标志位
不要使用stop或者destroy等过时或者jdk不建议使用的方法
定义一个boolean标志符默认值为true 设置一个方法停止线程 flag=false 转换标志符
运行线程时到一定的条件转换标志符,使其退出线程
2.线程睡眠
Thread.sleep(100);
3.线程让步
礼让线程,让当前正在执行的线程进入就绪状态让系统重新调度一次,但是不一定成功,看cpu调用
4.线程插队
jion等待此线程完成后,在执行其他线程
可以把jion理解成vip一样
5.线程优先级
线程优先级用数字表示,范围1-10
数字越高被cpu调动的可能性更大
6.线程同步
并发:同一个对象被多个线程同时操作
线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程在使用
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized ,当一个线程获得对象的排列锁,独占资源,其他线程必须等待,使用后释放锁即可. 存在以下问题:
◆一 个线程持有锁会导致其他所有需要此锁的线程挂起;
◆在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
◆如果一个优先级高的线程等待一 个优先级低的线程释放锁 会导致优先级倒置,引起性能问题.
7.线程池
java中经常需要用到多线程来处理一些业务,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理。java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中
好处:提高相应速度(减少创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次创建)
便于线程管理(...)
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多少时间后会终止
ExeutorService:真正的线程池接口,常见子类ThreadPoolExecutor
Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现