多线程底层原理
多线程底层原理
⽂章⽬录
那,各位之前有没有听过⼀句话叫做,⼀个CPU在同⼀个时间⽚只能执⾏⼀个程序;
什么意思呢?
就是,你的程序是不是都运⾏在⼀个CPU上啊,那你真正⼀个CPU在同⼀个时间⽚⾥是不是只能执⾏⼀个程序呀,那这个程序究竟要执⾏
那个程序,是不是就需要通过线程之间时间⽚的⼀个争抢;
时间⽚:微⼩的时间段;
多线程说⽩了就是时间⽚的争夺,那个线程获取了时间⽚,就执⾏那个线程的代码;
假设,t1线程先获得时间⽚,那么,t1线程就优先执⾏;
但是,它不可能拿着那个时间⽚不放吧,因为在CPU执⾏的过程中,底层运⽤轮循制的;
多线程执⾏的时候,CPU分配时间⽚是采取轮循的⽅式进⾏分配的;
就是轮流,有点像值⽇的时候,轮流值⽇⼀样;
那,CPU在分配时间⽚的时候,第⼀个t1先抢占到了之后,他先执⾏了⼀段时间之后,CPU把这个t1执⾏完了以后,CPU是不是接着把时
间⽚分配给t2去执⾏了;
那事实上,也是t2也在去抢占时间⽚;
当t1执⾏完毕后,那么,CPU就将迎来新的⼀轮争夺,这个时候t2抢到了,就开始执⾏t2的代码;
这就是多线程的底层执⾏原理;
多线程它在本质上运⾏的时候,他是同时执⾏的,还是轮流执⾏的呢?
肯定不是同时执⾏的,也就是不是我们常说的并发执⾏;那在你们看来,实际就是宏观上你来看就是同时执⾏,但是在微观上是不是的;
线程的状态
线程总共有五种状态;
第⼀个状态新建状态
新建状态,就是你新建⼀个线程是的状态,也就是你新建了⼀个线程但还没有启动时的状态;
当线程执⾏start⽅法的时候,就会进⼊就绪状态;
第⼆个状态就绪状态
进⼊就绪状态的时候,事实上就是准备抢占CPU的时间⽚;
⼀旦抢占到了CPU的时间⽚它就会⽴即进⼊运⾏状态;
第三个状态运⾏状态
当线程抢占到了CPU时间⽚的时候,它才会运⾏,所以第三个状态是,运⾏状态;
在它的运⾏状态中,还有可能执⾏⼀个代码,();睡眠;
就是在你执⾏的时候,突然让你睡眠了,我都让你这个线程睡眠了,你还有必要去争夺这个CPU资源吗?
就肯定没有必要再去争夺这个CPU资源了,那这个时候你就需要释放CPU啊,对不对,你释放之后,你下次再运⾏的时候,你就需要重新
获取CPU的时间⽚,所以这种状态就叫做堵塞状态;
第四个状态堵塞状态与sleep⽅法
想让线程阻塞,最常⽤的⽅式就是使⽤sleep,⽤sleep这个⽅法,可以使运⾏中的线程回到就绪状态;
因为它需要重新抢占CPU资源的,所以,sleep状态的最终⽬的是让改线程回到就读状态;
就⽐如,我现在想让这个线程,进我想让它每次进⼊run⽅法中的for循环打印⾥写⼀个睡眠,⼀遍循环遍历输出,⼀边睡眠看会发⽣什么:
我在run⽅法中业务写完后,我们测试⼀下该线程:
在上图中,可以发现,我同时调⽤了两次start⽅法,说明,我执⾏了两次我⼀次性开启了两次线程,并且执⾏了两次,我们看看会不会出
现交替执⾏的情况:
从输出结果来看,确实交替执⾏了并且,是俩俩执⾏的:
每过⼀秒,就会执⾏⼀次:
我就不继续演⽰了;
所以,我们从中可以看出,不管哪个线程过来,t1也好t2也好,执⾏的时候,均睡眠⼀秒钟,睡眠完⼀秒钟之后,谁先醒了,谁就继续向下
执⾏,这个就是到点⾃然醒的;
也可以使⽤join来造成线程堵塞;
join
刚刚,我们在上⾯介绍了sleep,我们来看看join;
join():是线程加⼊
它底层执⾏的是,当你在执⾏⼀个线程的时候,如果遇到其他线程加⼊,则会先执⾏加⼊的线程,直到的加⼊的线程执⾏完成,才会继续执
⾏原来线程的任务;
什么意思呢?
就是说,还是上⾯那个t1,与t2的例⼦,那假设说,t1在执⾏的过程中,突然遇到了⼀个代码,这时候,就会在这个时间⽚,优先执
⾏t2的线程;
join()⽅法可以给⼀个参数,参数代表执⾏的毫秒;
要正确的理解
阻塞当前线程直⾄*this所标识的线程结束其执⾏。
*this所标识的线程的完成同步于对应的从join()成功返回。
*this⾃⾝上不进⾏同步。同时从多个线程在同⼀thread对象上调⽤join()构成数据竞争,导致未定义⾏为。
也就是说,在哪⾥执⾏join()前提是可以join就在哪⾥阻塞
第五个状态死亡状态
线程执⾏完了,或因异常退出了,都会结束⽣命周期,这就是死亡状态;
挂起和睡眠是主动的,挂起恢复需要主动完成,睡眠恢复则是⾃动完成的,因为睡眠有⼀个睡眠时间,睡眠时间到则恢复到就绪态。⽽阻塞
是被动的,是在等待某种事件或者资源的表现,⼀旦获得所需资源或者事件信息就⾃动回到就绪态。
睡眠和挂起是两种⾏为,阻塞则是⼀种状态。
所以不管是join(),sleep()wait()等⾃⼰操作的主动⾏为都是让线程取阻塞(到达某种状态),⽽这个动作⼜被分为休眠和挂起
⾸先这些术语都是对于线程来说的。对线程的控制就好⽐你控制了⼀个雇⼯为你⼲活。你对雇⼯的控制是通过编程来实现的。
挂起线程的意思就是你对主动对雇⼯说:“你睡觉去吧,⽤着你的时候我主动去叫你,然后接着⼲活”。
使线程睡眠的意思就是你主动对雇⼯说:“你睡觉去吧,某时某刻过来报到,然后接着⼲活”。
线程阻塞的意思就是,你突然发现,你的雇⼯不知道在什么时候没经过你允许,⾃⼰睡觉呢,但是你不能怪雇⼯,肯定你这个雇主没注意,
本来你让雇⼯扫地,结果扫帚被偷了或被邻居家借去了,你⼜没让雇⼯继续⼲别的活,他就只好睡觉了。⾄于扫帚回来后,雇⼯会不会知
道,会不会继续⼲活,你不⽤担⼼,雇⼯⼀旦发现扫帚回来了,他就会⾃⼰去⼲活的。因为雇⼯受过良好的培训。这个培训机构就是操作系
统
线程分配
1.任务并⾏:每个线程执⾏代码的⼀部分
2.数据并⾏:每个线程处理⼀部分数据
3.线程间潜在问题就是修改共享数据,致使不变量遭到破坏;只要系统中的不变量不受什么影响就不会出现什么问题.如果会产⽣不好的
锁
标不标记为互斥都是根据代码来说的。
只要是调⽤函数的实体没有被成功上锁(⽐如说函数返回引⽤),那么实体调⽤函数部分的代码就是没有被成功上锁的。
切勿将受保护数据的指针或引⽤传递到互斥锁作⽤域之外,⽆论
是函数返回值,还是存储在外部可见内存,亦或是以参数的形式传递到⽤户提供的函数中去。其实所谓的锁也就是对于互斥量的获取
本文发布于:2022-11-27 13:45:16,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/31342.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |