线程(2)

本文探讨了并发排序在多核和单核环境下的性能比较,指出并发排序并不总是优于串行排序,尤其是在创建和销毁线程、线程调度存在开销的情况下。同时,介绍了线程的基本知识,包括Thread.yield()的作用,线程的控制策略,以及何时应该考虑使用多线程。文章还提到了线程间的数据共享、JVM内存区域划分,以及每个线程拥有独立PC和栈的原因。
摘要由CSDN通过智能技术生成

目录

join(补充)

1.多核环境下,并发排序的耗时<串行排序的耗时

2.单核环境下,并发排序的耗时也能小于吗?

3.并发排序的耗时就一定小于串行的吗?

Thread下的常见方法:

Tread.yield() 

线程的控制

应该考虑使用多线程的场景:

线程小结的基本知识

线程之间的数据共享——线程通信 

JVM下的内存区域划分

为什么每个线程都有自己的PC

为什么每个线程都有自己的栈


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对象关于类的对象),静态属性,保存在方法区中,所以是线程之间的共享

对象(对象的内部属性),保存在堆中,所以是线程之间共享的

前提是线程持有该对象的引用

变量本质是对一块内存的抽象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值