引入多线程的代价

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/geekerhw/article/details/52268382

在现代计算机系统中,使用多线程和并发技术无疑是提升系统运行效率的重要手段之一,他可以最大化的利用cpu的空闲时间,提升系统的吞吐量和速率,但是,引入这些诱人的技术代价也是不容忽视的,比如上下文切换带来的额外开销,内存同步造成的损耗等等,如果这些诱人的技术带来的性能提升不足以掩盖他们的缺点时,我们的工程系统就需要立刻被重新设计,生于忧患死于安乐,因此,在知晓其好处之前我们更应该洞察其缺点

上下文切换

这里写图片描述

  • 当多个线程在Ready和Running两个状态之间互相转换(时间片轮转模式)的时候就发生了所谓的上下文切换,操作系统会将正在使用cpu的线程上下文先保存到TCB中,然后将新调度进来的上下文设置为当前上下文
  • cpu会根据调度器中的当前上下文去执行线程,拿到需要执行的线程后首先做的事是根据此线程的TCB中的信息去恢复此线程之前的状态,这些操作需要频繁的去访问JVM和操作系统共享的数据结构,一个cpu分配给一个线程的时间片是一定的,我们在这些操作上消耗越多,给线程执行真正的任务的时间就越少
  • 根据java并发编程实战上所讲,在大多数的通用处理器中,上下文的切换开销相当于5000 - 10000个时钟周期,大概在几微秒左右

内存同步

  • 安全性与活跃性之间永远存在制衡,为了保证并发情况下的安全性,相应的同步策略是必不可少的,Java中synchronized和volatile提供的可见性保证中会使用一些特殊的汇编指令,叫做内存屏障,它可以刷新缓存,使缓存无效,从而保证每个线程读到应用了此技术的对象时会直接从内存中读取而不是高速缓存(本地内存)中,这样就可以保证多个线程可以立刻看到关于此对象最新的改动
    这里写图片描述

  • 比较可惜的是,这项技术会抑制一些现代编译器的优化,在内存屏障里的代码段,他们是不能被重排序的,并且同步会增加共享内存总线上的通信量,总线的带宽是有限的,所有的处理器都将共享这条总线,如果有多个线程竞争同步带宽,那么所有使用了同步的线程都会受到影响
    这里写图片描述

阻塞

  • 引入多线程后就会存在竞争,在锁上发生竞争时,失败的线程肯定会被阻塞,JVM在实现阻塞行为时采用自旋等待或者被系统挂起的方式,这两种方式效率的高低取决与上下文切换的开销以及线程在成功获取锁之前需要等待的时间,如果等待时间很短,则时候自旋方式,反之,则适合挂起的方式.有些JVM将根据对历史等待时间的分析数据在两者之间动态的选择,但是大多数的JVM在等待锁时都选择了挂起的模式
  • 当一个线程因阻塞被挂起时,他会产生两次额外的上下文切换,以及必要的操作系统操作和缓存操作(上下文切换会导致高速缓存中的内容丢失),这些都是阻碍系统高速运行的原因
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页