栈和栈帧
在没有多线程(执行流)+没有外部输入的情况下,程序的运行其实就是一个状态机
int a = 3,b =7; 状态
a = a*10; b = b*10; 进行状态迁移
现在a = 30,b =70; 新的状态
方法调用(函数调用)
main(){ add(int a,int b){
int x = 10,y = 20; return a+b;
int z = add(x,y); }
}
变量由2个变成4个,然后又变成2个 状态的改变
这些状态出现的顺序符合FILO(使用栈去维护这些框)
栈:当前执行流的当前时刻(时间停止状态时)的状态框有哪些(现实方法的调用次序)
框:栈帧(frame)存储了一些运行该方法时需要的一些临时数据(主要就是具备变量)
等待线程停止的join方法
1.join() 等待线程死去
2.join(long mills)等待线程死去,但最多等到...毫秒
3.join(long mills,int namos)时间单位更精确
1.多核环境下,并发排序的耗时<串行排序的耗时
单线程一定能跑在一个CPU(核)上,多线程意味着可能工作在多个核上(核亲和性)
2.单核环境下,并发排序的耗时也能小于吗
OS调度单位是线程,但我们衡量耗时是以进程为单位的
即使在单核环境下,并发的耗时也可能较少
本身,计算机下就有很多线程在等待分配CPU,比如,现在有100个线程,公平的情况下,主线程只会被分配1/100的时间。
当并发时,我们使用4个线程分别排序,除其他99个之外,计算机中共有99 +14 = 103个线程,我们4个线程属于同一个进程,分给我们进城的时间占比4/103 > 1/100
即使单核情况下,我们一个进程中的线程越多,被分到的时间片就越多
线程越多越好吗?
不是的,创建线程本身也要耗时间。 即使理想情况下,不考虑其他耗时,极限也就是100%
线程调度也需要耗时(OS从99个线程中跳出一个的耗时和从9999中挑出一个的耗时一定是不同的)
CPU是公共资源,写程序时也需要考虑公德心。如果是好的OS系统,可能也会去避免这个问题
3.并发排序的耗时就一定小于串行吗
不一定,
串行的排序: t = t(排区间1)+ t(排区间2)+t(排区间3)+t(排区间4)
并发的排序:t = 4*t(创建线程) +t(排区间1)+ t(排区间2)+t(排区间3)+t(排区间4)+4*(销毁)
为什么我们要写多线程代码?
提升整个进程的执行速度(尤其计算机密集型的程序)
Thread.yeild():主动让出CPU的资源
用于执行一些耗时比较久的计算任务,防止计算机出现”卡顿“现象,主动让出CPU给OS内的其他进程。让出CPU,会引导OS进行新的一轮的线程调度(上下文切换 = 保存当前线程的PC)以后,等我们被分配CPU时, 恢复我们之前保存的CPU * 现象:我们的代码是接着上一次的继续执行
线程是OS调度的单位
线程是OS分配CPU资源的单位
对程序员:线程是抢夺CPU的工具
线程的控制 ——通知线程
A叫B干活
1.暴力停止,直接killB,目前不采用了,因为不知道B工作的进行情况(不可控)
stop(); //deprecate v.不赞成,过时,被废弃的
2.graceful的方式就是和B进行协商
A给B主动发一个信号,代表B已经停止了
B在一段时间里,看到了停止信号,就可以主动把手头上工作做到一个阶段完成,主动退出
b.interrupt(); //只是发了停止标志,并不会影响B运行
B如何感知有人让它停止呢?
case1:B正在正常执行代码,可以通过一个方法来判定、
静态方法 Thread.interruptd() ; //检测当前线程是否已经被终止
case2:B可能正处于休眠状态(sleep、join),意味着B无法独立执行
此时,JVM的处理方式是,以异常形式,通知B:IntterruptedException
当一个执行流因故阻塞时,我们需要一个新的执行流(线程)
不停的读用户输入,计算斐波那契数列。(我们采用递归,性能很慢,造成类似阻塞的场景)
应该考虑使用多线程的场景:
1.计算密集性的任务,为了提升速度,可以引入多线程
2.当一个执行流阻塞时,还能处理其他任务,引入多线程(这个场景并不多见)
总结
1.线程:代表一个独立的执行流,属于某个进程,是OS进行调度的基本单位(分配CPU资源)
2.OS为啥要引入线程?
分离 承载资源的基本单位+调度的基本单位 (早期进程)
承载资源的基本单位 现代进程
调度的基本单位 线程
3.开发者的角度,啥时候需要用到多线程开发?
提升效率或者 阻塞的场景
4.线程在java中的表示+ 属性+常见方法