Java高并发(一)--走进并行世界

何去何从的并行计算

并行计算遇到的问题

  1. Linus Torvalds认为并行计算只能用于图像处理和服务端编程

  2. 摩尔定律失效:CPU 主频的提升遇到了一些暂时不可逾越的瓶颈

并行计算的进步

  • 新摩尔定律:每24/18月,cpu核心数翻一番

并行的基本概念

同步:同步方法一经调用,调用者必须要等到方法结束后才能进行后续操作
异步:类似消息传递,异步方法一旦开始,调用就会返回,调用者可进行后续操作
异步与同步
并发:多任务交替执行
并行:多任务同时执行(只能出现多cpu系统中)

临界区:一种公共资源,可以被多个线程使用.

  1. 一次只能被一个线程使用,其他线程只能等待
  2. 在并行程序中,临界区是被保护的对象

阻塞:一个线程占用了临界区资源,其他需要该资源的线程将会在临界区等待.等待导致线程挂起.
非阻塞: 没有一个线程可以妨碍其他线程执行,所有线程都会前向执行.

死锁:多个线程占用其他线程的资源,又等待其他线程已占用的资源,导致所有线程都不能前向执行.
饥饿:线程由于某种原因无法获取需要的资源,导致一直无法执行

  1. 线程的优先级太低,资源一直被优先级高的线程抢占
  2. 死锁也会导致饥饿线程(饥饿有可能在未来一段时间解决)

活锁:多个线程都将资源谦让给其他线程,导致没有一个线程获得所有资源而向前执行

并发级别

并发的级别:阻塞,无饥饿,无障碍,无锁,无等待

阻塞

一个线程是阻塞的,那么其他线程释放资源前,该线程无法前向执行.

阻塞的实现方式:

  1. synchronized
  2. 重入锁

无饥饿

  • 对于非公平锁,高优先级的线程优先获取资源,导致低优先级的线程无法获取资源产生饥饿.
  • 可通过公平锁消除饥饿.

无障碍

无障碍的特点

  • 最弱的非阻塞调度
  • 两个线程若都无障碍运行,则不会因为临界区导致阻塞
  • 一旦将数据写坏,则进行回滚

无障碍调度

阻塞的控制方式是悲观的,非阻塞调度是乐观策略

一种可行的非阻塞调度策略

依赖"一致性标记"

  1. 线程操作前读取并保存该标记
  2. 操作完成后,再次读取该标记,判断是否与保存的标记一致.
    若一致,则资源访问没有冲突,并更新标记
    若不一致,则说明资源访问发生冲突,需要重新操作

无锁

无锁的特点

  • 无锁的并行都是无障碍的
  • 无锁的并发保证必然有一个线程在有限步内完成操作,离开临界区

无锁的实现

  • 无锁调用中一般会包含一个无穷循环
  • 无锁并行保证有一个线程在竞争中胜出,离开临界区
    while (!atomicVar .compareAndSet(localVar, localVar+1)) {
    	localVar = atomicVar.get();
    }
    
  • 如果某一线程一直竞争不到资源,也会发生饥饿现象

无等待

无等待特点

  • 要求所有线程都在有限步完成,不存在饥饿现象

无等待实现

  • RCU(read copy update)
    1. 数据读是无等待的
    2. 写数据时修改的是数据的副本,在合适时机写回数据

并行的两个定律

并行程序的目的

  1. 获取更好的性能
  2. 业务要求多个执行的实体

加速比定义
加 速 比 = 优 化 前 系 统 耗 时 优 化 后 系 统 耗 时 加速比=\frac{优化前系统耗时}{优化后系统耗时} =

Amdahl 定律

加速比计算

  • 如果 CPU 处理器数量趋于无穷, 那么加速比与系统的串行化比例成反比

Gustafson 定律

在这里插入图片描述

  • 串行化比例很小,并行化比例很大,加速比就是处理器的个数

两个定律是否矛盾

  • 为了提高系统的性能,有两种方法
    1. 增加 CPU 处理器的数量
    2. 提高系统内可并行化的模块比重
  • Amdahl定律认为增加cpu能够减少并行任务时间
  • Gustafson定律认为增加cpu能够增加并行时间的任务量(与之对应单cpu的并行时间增长)

JMM(Java内存模型)

原子性

原子性是指一个操作不能中断,一旦开始就不会被其他线程干扰.
对于32位系统,longdouble的读写不是原子性的

可见性

可见性是指一个线程修改一个共享变量时,其他线程也能看到这个修改.

不可见性产生的原因

  1. cpu对变量的优化,将变量存入cache或寄存器
  2. 指令重排
    指令重排

有序性

有序性是指程序执行的顺序按照代码的先后顺序执行.

指令重排会打乱程序的有序性
  • 指令重排保证串行语义一致,但不保证多线程间语义一致
  • 指令重排是否发生,发生的时机都无法预测
指令执行的步骤
取指IF
译码与取操作数ID
执行或计算地址EX
存储器访问MEM
写回WB
指令流水线

指令可以分割成多个在不同硬件中完成的步骤,可采用流水线执行可以提高效率流水线指令

图5-指令流水线可以减少指令等待的时间
指令流水线一旦断流,所有硬件进入停顿期.再次载满流水线需耗费几个指令周期,造成巨大性能损失.

防止指令断流

  1. 汇编指令等待(图5中的X)

  2. 指令重排

    对以下指令优化
    a=b+c
    d=e-f

重排前
重排策略
重排后

重排前,SUB和ADD需要等待操作数
重排后,将加载变量提前到SUB和ADD前,充分利用等待的指令周期

不能重排的指令:Happen-Before规则

详情可见

  1. 单线程原则:同一个线程中,书写在前面的操作happen-before后面的操作。
  2. 锁的原则:同一个锁的unlock操作此锁的lock操作。
  3. volatile的原则:对一个volatile变量的写操作happen-before对此变量的任意操作。
  4. 传递性原则:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
  5. 线程启动的原则:同一个线程的start方法happen-before此线程的其它方法。
  6. 线程中断的原则:对线程interrupt方法的调用happen-before被中断线程的检测到中断发送的代码。
  7. 线程终结的原则:线程中的所有操作都happen-before线程的终止检测。
  8. 对象创建的原则:一个对象的初始化完成先于他的finalize方法调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值