[转帖]并发编程大纲

并发编程大纲

https://www.jianshu.com/p/2075b452bc46

并发编程

为什么需要并发编程

目的

提高系统性能

本质

软件是一组特定计算机指令的集合,是架构在硬件之上的对特定业务的一种表达和计算的抽象;所以并发编程底层的焦点就是如何执行;也就是cpu如果管理指令的执行;cpu时间分片来管理线程执行

并发编程优势

  1. 资源利用率

    cpu 多核资源;线程运行到需要等待的时候,等待的同时,执行其它程序

  2. 公平性

    用户和程序对计算机拥有同等的使用权;一种高效的运行方式就是通过粗粒度的时间分片,是这些用户和程序能共享计算机资源

  3. 便利性

    建模简单性、异步事件的简化

  4. 提高相应速度

编发编程带来的问题

  1. 线程安全问题

    共享变量的控制

  2. 活跃性

    线程安全关注的是程序不会产生意想不到的结果;活跃性关注的是线程总是向正确的方向执行;

    所以会出现死锁(资源共享竞争)、饥饿(线程永远执行不到,优先级底等)、活锁(没有导致阻塞,但是重复尝试-失败-尝试-失败)等现象

  3. 性能问题

    活跃性意味着某件正确的事情最终会发生;而性能则是关注是希望正确的事情尽快的发生。

线程安全

当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类时线程安全的。

编写线程安全代码核心

对状态的操作进行管理;特别是对共享的和可变的状态访问

共享:可以由多个线程同时访问

可变:变量的值在其生命周期内可以发成变化

一个对象是否需要时线程安全的,取决于它是否被多个线程访问

线程安全-共享变量控制

  1. 不在线程之间共享该状态变量
  2. 将状态变量修改为不可变的变量
  3. 在访问状态变量时使用同步

没有共享变量的对象,称为无状态对象;无状态对象一定是线程安全的

如何保证线程安全

  1. 同步

    • 加锁

    • volatile (cas)

    加锁机制既可以保证可见性又可以确保原子性,而volatile变量只能确保可见性

    避免使用同步的方式就是不共享数据(线程封闭)

    线程封闭:封闭在线程中的对象不会从线程中逸出(如:线程池、ThreadLocal)

    • 栈封闭:只能通过局部变量才能访问对象(基本类型)
    • ThreadLocal
  2. 使用不可变对象

    不可变对象,只有一种状态,并且该状态有构造函数来控制

  3. 原子性

    竟态条件:不恰当的执行时序而出现不正确的结果(共享状态发生了竞争)

    常见的竟态条件类型就是"先检查后执行"(如单例)

    如何避免竞态条件

    复合操作:包含了一组必须以原子方式执行的操作以确保线程安全(先检查后执行以原子方式执行,单例的双重校验)

    如何保证原子性呢

    锁来保护状态

    内置锁(Synchronized)

    同步(Synchronized)除了实现原子性,还有另外一个重要的方面:内存可见性

    加锁的含义不仅仅局限于互斥行为,还包括内存可见性

  4. 可见性

    volatile

    final (安全发布)

  5. 顺序性

    happen-before

发布对象

发布对象:是一个对象能够被当前范围之外的代码所使用

对象逃逸:一种错误的发布。当一个对象还没有构建完成时,就使他被其它线程所见

安全发布对象

  1. 在静态初始化块函数中初始化一个对象引用
  2. 将对象的引用保存到volatile类型域或者AtomicReference对象中
  3. 将对象的引用保存到某个正确构造对象的final类型域中
  4. 将对象的引用保存到一个由锁保护的域中

 

知识体系

  • 线程安全
  • 线程封闭
  • 线程调度
  • 同步容器
  • 并发容器
  • JMM
  • AQS
  • JUC

高并发解决思路

  • 扩容
  • 缓存
  • 队列
  • 拆分
  • 服务降级与熔断
  • 数据库分库分表

概念

并发

同时拥有两个或者多个线程,如果程序在单核处理器上运行,多个线程将交替执行,这些线程是同时“存在”的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核上,因此可以同时运行。

高并发

高并发(High Concurrency)是互联网分布式系统架构中必须考虑的因素之一,通常指,通过设计保证系统同时并行处理很多请求。

并发和高并发区别

并发:多个线程操作相同的资源,保证线程安全,合理使用资源

高并发:服务能同时处理很多请求,提供程序性能

JMM(Java Memory Model)规定

规定了一个线程如何和何时由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量

jvm堆:java运行时的数据区,由垃圾回收来负责的;可以动态分配内存大小,对象生存期无效告诉编译器;正是因为动态分配内存,所以存储数据会慢些

栈:存取速度比堆要快,仅此与计算机的寄存器;主要存储基本变量和堆中的引用地址

java内存模型的-同步八种操作

lock(锁定):作用与主内存的变量,把一个变量表示为一条线程独占状态

unlock(解锁):作用与主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才以被其它线程锁定

read(读取):作用与主内存的变量,把一个变量从主内存传入到线程的工作内存中,以便随后的load动作使用

load(载入):作用与工作内存的变量,它把read操作从从内存中得到的变量放入工作内存的变量副本中

use(使用):作用与工作内存的变量,把工作内存中的一个变量值传递给执行引擎

assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量

store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作

write(写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中

并发测试工具

  • Postman: http请求模拟工具
  • Apache Bench(AB):Apache附带的工具,测试网站性能
  • Jmetter:Apache组织开发的压力测试工具

线程安全性

当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就成这个类时线程安全的。

原子性:提供互斥访问,同一时刻只能有一个线程来对它进行操作

可见性:一个线程对主内存的修改可以及时的被其它线程观察到

有序性:一个线程观察其它线程中的指令执行顺序,由于指令重排序的存在,该观察结构一般杂乱无序

猜你喜欢

转载自www.cnblogs.com/jinanxiaolaohu/p/12898829.html