并发编程实战


转载: https://www.cnblogs.com/wadmwz/p/10504164.html
并发编程的三个核心问题:

  1. 分工 : 高效的拆解任务分给线程
  2. 同步 : 线程之间的协作
  3. 互斥 : 保证同一时刻只允许一个线程访问共享资源

这个其实不难理解,做个简单的比喻,我们团队做一个项目的时候肯定是先分配任务(分工),然后等到任务完成进行合并对接(同步),在开发过程中,使用版本控制工具访问,一个代码只能被一个人修改,否则会报错,需要meger(互斥).
核心: 分工(拆分) - 同步(一个线程执行完成如何通知后续任务的线程开始工作) - 互斥(同一时刻,只允许一个线程访问共享变量)
全景:
在这里插入图片描述

并发编程为啥好难?

每一中技术的出现都有他出现的必然性,对于并发来说无疑是提高性能,那单线程为啥就不能提高性能,原因就在于CPU,内存和IO设备三者的速度差异太大,举个例子来说: CPU一天,内存一年,IO一百年; 而木桶理论告诉我们程序的性能是由短板决定,所以只要合理的平衡三者的速度差异,就可以提高性能.

并发编程问题的源头
  1. 缓存导致的可见性: 对于单CPU来说,缓存是可见的,也就是说多个线程同时操作,CPU会从内存读取数据,线程更新数据到CPU,CPU写入内存,线程和CPU进行交互,这个操作每个线程之间是可见的.
    但是对于多CPU来说,多个线程操作不同的CPU,不同的CPU操作同一个内存,这会导致操作的不可见性,就出现了问题.(说下可见性的概念: 一个线程对共享变量的修改,另一个线程能够立刻看到,这就是可见性)
  2. 线程切换带来的原子性问题: 原子性是一个或多个操作在CPU执行的过程中不被中断的特性. 那为什么会中断呢?原因就在于提高性能,就和现在的计算机一样,是分时间片来进行任务切换,同时听歌和敲代码,看似是同时发生,其实不是,知识任务之间切换的非常快,做到了看似同时进行.在高级程序中,一个看似简单的操作可能需要多条CPU指令来完成,不如说count += 1;CPU指令至少三个,从内存中拿到count值到寄存器,在寄存器中进行加一操作,将结果写入内存,这个过程中可能会发生任务间的切换,比如说另一个线程在写入内存前有进行了一次++操作,这个时候结果就不是想要的结果了,可能例子不合适,但是这个意思就是这个. 而原子性就是保证高级语言层面保证操作的原子性.
  3. 编译优化的有序性问题: 有序性指的是程序按照代码的先后顺序执行. 看起来没问题,本来就应该这样,其实不然,在JVM的知识中有一个叫重排序,就是编译器为了优化性能,有时会改变程序中语句的先后顺序,大部分情况下编译器调整后的顺序是不会影响程序的最终结果,不过也有特殊情况,如下:
public class Singleton {
  static Singleton instance;
  static Singleton getInstance(){
    if (instance == null) {
      synchronized(Singleton.class) {
        if (instance == null)
          instance = new Singleton();
        }
    }
    return instance;
  }
}

上面是经典的双重检查创建单例对象,在我们的印象中new的操作应该是: 分配内存,在内存上初始化对象,地址赋值. 实际上优化后是: 分配内存,地址赋值,初始化. 优化后的顺序就会出现问题,地址赋值后发生了线程切换,这时候其他线程读取到了对象不为null,但是实际上只有地址,这个时候访问成员变量就会出现空指针异常,这个就是编译优化可能会出现的问题.解决此问题的方法就是使用volatile关键修饰单例对象的变量,因为在构造线程初始化Something和返回值之前,将发生事前关联。读取它的线程。此关键字要在JDK1.5之后才会有效
也就是说,很多的并发Bug是由可见性,原子性,有序性的原理造成的,从这三个方面去考虑,可以理解诊断很大部分一部分Bug. 缓存导致可见性问题,线程切换带来的原子性,编译优化带来的有序性,本质都是提高程序性能,但是在带来性能的时候可能也会出现其他问题,所以在运用一项技术的时候一定要清楚它带来的问题是什么,以及如何实现.

下面就是利用volatile和synchronized实现同步和互斥的讲解

从硬件方面讲解volatile和synchronized关键字的语义

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值