zoukankan      html  css  js  c++  java
  • 多线程专题

    一、基础概念

    1、什么是进程?什么是线程?

      进程是os调度的最小单元,比如启动一个java程序就会创建一个进程,线程是cpu调度的最小单元,一个进程可以创建很多个线程,这些线程有各自的计数器、堆栈、局部变量等属性。

    2、什么是JMM模型?

      java内存模型(Java Memory Model),并不真实存在,描述的是一组规则或规范,这组规范定义了各个变量的访问方式。JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存,用于存储线程私有的数据,JMM规定所有变量都存储在主内存,主内存是共享区域,所有的线程都可以访问,但是线程变量的操作必须在工作内存中进行,首先将变量拷贝到自己的工作内存空间,然后进行操作,操作完成后回写主内存。不同线程之间无法访问对方的工作内存,线程间的通信必须通过主内存完成。

      主内存:实例共享区域,包括类信息、常量、静态变量。由于是共享数据区域,多条线程对同一个变量进行访问时可能会发生线程安全问题。

      工作内存:存储当前方法的所有本地变量信息副本,每个线程只能访问自己的工作内存,即线程中的本地变量对其他线程是不可见的,就算两个线程执行的是同一段代码。

    数据同步的八大原子操作

    1. lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
    2. unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
    3. read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
    4. load(载入):作用于工作内存中的变量,把read操作从主内存中获取到的变量写入到工作内存的副本中
    5. use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
    6. assign(赋值):作用于工作内存中的变量,把执行引擎接收到的值传送到主内存的变量
    7. store(存储):把工作内存中的值传送到主内存,以便后续的write操作
    8. write(写入):把store操作从工作内存中一个变量的值写入到主内存

    同步规则分析

    1. 不允许一个线程无原因的(没有发生过任何assign操作)把数据从工作内存同步回主内存中
    2. 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化的变量。即对一个变量实施use和store操作之前,必须先自行load和assign操作
    3. 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,lock与unlock必须成对出现
    4. 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load和assign操作
    5. 如果一个变量事先没有被lock操作锁定,则不允许对他执行unlock操作
    6. 执行unlock之前,必须先把此变量同步到主内存中(执行store和write操作)

    并发编程的可见性,原子性与有序性问题

    1. 原子性:是指一个操作是不可中断的,即使多线程环境下,一旦开始就不会被其它线程影响。基本数据类型都是原子操作(32为操作系统的long和double不一定,因为long和double是64位存储单元,虚拟机读取到的可能是半个变量的值)
      解决:通过syncchronized和lock能保证任意时刻只有一个线程访问该代码块
    2. 可见性:理解指令重排之后,可见性就容易理解了,指的是,当一个线程修改了某个共享变量的值,其它线程是否能够马上得知这个修改的值
      解决:volatile关键字可保证可见性,syncchronized和lock也能保证可见性,因为他们可以保证同一时刻只有一个线程能访问共享资源,并在释放锁之前将修改值刷新到主内存中  
    3. 有序性:如果是多线程环境下,指令重排后的顺序与原指令未必一致
      解决:valatile可以保证一定的有序性,syncchronized和lock可以保证有序性,相当于同一时刻只有一段程序执行同步代码,自然保证了有序性

    happens-before原则

    1. 程序顺序原则:即在一个线程内,必须保证语义的串行性,也就是说按照代码顺序执行
    2. 锁规则:解锁动作必须在加锁之前,那么加锁动作也必须在解锁之后
    3. volatile原则:简单理解就是volatile变量在每次线程访问时,都强迫从主变量中读该变量的值,而当该变量发生变化时,又会强迫将最新的值刷新到主内存中
    4. 线程启动规则:start方法先于他的每个动作,A在B执行start方法之前修改了共享变量的值,那么这个值对线程B可见
    5. 传递性:A先于B,B先于C,那么A必然先于C
    6. 线程终止规则:线程所有的操作先于线程的终结,Thread.join()的作用是等待当前执行的线程终止
    7. 线程中断规则:可以通过Thread.interrupted()方法检测线程是否中断
    8. 对象的终结规则:结束先于finalize()方法。

    volatile内存语义

    1. 保证被volatile修饰的共享变量对所有的线程总数是可见的,也就是当一个线程修改了被volatile修改的变量值,新值总是可以被其他线程立即得知,但是volatile无法保证原子性
    2. 禁止指令重排优化
      memory = allocate();//1、分配对象内存空间
      instance(memory);//2、初始化对象
      instance = memory; // 3、设置instance指向刚分配的内存地址
      2、3之间可能存在指令重排,而这就产生了一致性的问题,volatile可以禁止这种指令重排

    3. volatile重排序规则:
      • 第二个操作是volatile写时,不管第一个操作是什么,都不能重新排序。这个规则确保volatile写之前的操作不会被编译器重排到volatile读之前
      • 当第一个操作时volatile读时,不管第二个操作是什么,都不能重新排序。这个规则缺包volatile读之后的操作不会被编译器重排到volatile读之前
      • 第一个是volatile写,第二个是volatile读时不能重排序
    岁月本长而忙者自促;天地本宽而卑者自隘;风花雪月本闲,而劳忧者自冗;天行健,君子以自强不息;地势坤,君子以厚德载物;宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒.不妄取,不妄予,不妄想,不妄求,与人方便,随遇而安
  • 相关阅读:
    Vue动态路由配置-router.addRoute
    安装nginx(Centos和docker)
    前后端分离跨域问题解决方案
    centos7 部署 gitlab
    date命令使用方法
    电脑明明安装了模块,但是pycharm还是找不到怎么办
    shell脚本中字符串截取问题
    linux中每登录一个终端,就会自动执行脚本
    腾讯文档中怎么添加二级缩进符号
    查看CPU某一核的情况
  • 原文地址:https://www.cnblogs.com/vvning/p/13805726.html
Copyright © 2011-2022 走看看