目录
join(补充)
1.多核环境下,并发排序的耗时<串行排序的耗时
单线程一定能跑在一个CPU(核)上,多线程以为着可能工作在多个核上(还包含核亲和性)
2.单核环境下,并发排序的耗时也能小于吗?
即使在单核情况下,我们一个进程中的线程越多,被分到的时间片是越多的
但是线程不是越多越好,因为创建线程也是需要时间的,即使在理想情况下,不考虑其他耗时,极限也是100%;线程调度也需要耗时(OS从99个线程中挑一个的耗时和从9999个线程中挑一个的耗时不同)
CPU是公共资源,写程序的时候也要考虑公德心,如果是好的OS系统,可能也会避免这个问题
3.并发排序的耗时就一定小于串行的吗?
不一定。
串行:t=t(排序间1)+t(排序间2)+(排序间3)+t(排序间4)
并行:t=4*(创建线程)+t(排序间1)+t(排序间2)+(排序间3)+t(排序间4)+4*t(销毁)
为什么要写多线程代码的原因之一:提高整个进程的执行速度(尤其计算密集性的程序)
Thread下的常见方法:
Tread.currentTread() 返回当前的引用
Tread.sleep()+TimeUnit.sleep() 做休眠(线程主动让出CPU,切换到阻塞状态)
Tread.yield()
让线程让出CPU 线程从运行->就绪状态
随时可以继续被调回CPU
public class Main {
public static class PrintWhoAmI extends Thread{
private final String who;
public PrintWhoAmI(String who)
{
this.who=who;
}
@Override
public void run() {
while(true){
System.out.println("我是"+who);
// if(who.equals("张三")){
// Thread.yield();
// }
}
}
}
public static void main(String[] args) {
PrintWhoAmI 张三=new PrintWhoAmI("张三");
PrintWhoAmI 李四=new PrintWhoAmI("李四");
张三.start();
李四.start();
}
}
yield主要用于执行一些耗时较久的计算机任务时,为让防止计算机处于”卡顿“的现象,时不时的让出一些CPU资源,给OS内的其他进程
如果线程执行一半时让出CPU,下次进入该线程时会咋样
让出CPU,会引导OS进行新的一轮线程调度(上下切换=保护当前线程的PC)
以后,等我们被分配CPU时,恢复我们之之前保存的CPU
现象:我们线程的代码是接着上一次的继续执行
线程是OS调度的单位
线程是OS分配CUP资源的单位
程序员角度来说:线程是抢夺CPU的工具
线程的控制
通知线程停止
(A找B干活,突发情况需要让B停止工作,即使分配它的任务没有完成)
1.暴力停止,直接杀掉B。
但是基本上已经不采用了。原因是直接杀掉B,不知道B是否把工作进行的如何了(不可控)
2.跟温和的方法就是和B进行协商。
A给B主动发一个信号,代表B已经停止了(发消息):
B在一段时间里,看到了停止信号之后,就可以主动,把手头的工作做到一个阶段完成,主动退出
B如何感知到有人让它停止 。
情况1:B正在正常执行代码,可以通过一个方法来判定
true:有人让我们停止 false:没人让我们停止
情况2:B可能正处于休眠状态(比如sleep,join),意味着B无法 立即执行Threadinterrupt()
此刻,JVM的处理方式是,以异常形式,通知B:InterruptedException,代表有人让我们停止,具体要不要停,什么时候停,怎么停,完全自己做主
当一个执行流因故阻塞时,我们需要一个新的执行流(线程)
应该考虑使用多线程的场景:
1.计算密集性的任务,为了提升整体速度,可以引入多线程
2.当一个执行流阻塞时,为了还能处理其他任务,可以引入多线程
线程小结的基本知识
线程之间的数据共享——线程通信
大部分场景下,几个线程之间是需要协调配合工作,一切完成一个总目标的。
线程之间需要进行数据交换
由于我们的线程都属于同一个进程,所以,共同享有OS分配过来的同样的资源(其中优先关注内存资源)
JVM下的内存区域划分
PC保存区
栈:虚拟机栈 本地方法栈
堆
方法区
运行时常量池
堆,方法区,运行时常量池是整个进程(JVM)只有一份。
PC(保存PC的值),栈(虚拟机栈,本地方法栈)是每个线程独一份。
加载的类和对象是大家共有的
为什么每个线程都有自己的PC
每个线程都是独立的执行流,下一条要执行的指令和其他线程无关 ,所以有自己的PC
为什么每个线程都有自己的栈
每个线程都是独立的执行流,有各自调用的方法链,有各自要处理的临时数据,所以栈也是独一份
在代码中
局部变量,保存在栈帧中,也就是保存在栈中,所以是线程私有。
类对象(class对象关于类的对象),静态属性,保存在方法区中,所以是线程之间的共享
对象(对象的内部属性),保存在堆中,所以是线程之间共享的
前提是线程持有该对象的引用
变量本质是对一块内存的抽象。