zoukankan      html  css  js  c++  java
  • java多线程的基础-java内存模型(JMM)

    在并发编程中,需要处理两个关键问题:线程之间如何通信,以及线程之间如何同步。通信是指线程之间如何交换信息,在命令式编程中,线程之间的通信机制有两种:内存共享和消息传递。
         同步是指程序中用于控制不同线程间的操作发生相对顺序的机制。在共享内存并发模型中,同步是显性进行的。程序员需要显性设置某段代码在线程之间的互斥执行。在消息传递的并发模型中,由于消息的发送必须在消息的接受之前,因此同步是隐性进行的。
         Java并发采用的是共享内存模型。
     
         Java内存模型(JMM)的关键技术点都是围绕着多线程的原子性、有序性、可见性来建立的。
     
         1. 原子性-Atomicity
         原子性是指一个操作是不可中断的。即使在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
         例如,对于一个静态变量i,有两个线程对其赋值,线程A给它赋值1,线程B给它赋值2,那么不管这两个线程如何工作,i要么是1,要么是2。线程A和B之间是没有干扰的,这就是原子性的一个特点,不可被中断。
         但是如果使用long类型(long类型是64位)的话,对于32位操作系统而言,long型数据的读写不是原子操作,也就是说,多个线程同时对一个long进行操作的话,线程之间的结果是有干扰的。
     
         2. 可见性-Visibility
         可见性是指当一个线程修改了一个共享变量的值,其他线程是否能够立即知道这个修改。对于串行程序来说,这个问题是不存在的,因为在任何一个步骤中修改了变量值,在后续的步骤中读取这个值,一定是修改后的。
         但是在并行程序中就不见得了。如果一个线程修改了变量值,其他线程未必能马上知道这个改动。A线程和线程B分别读取了变量i,A再对变量i操作,这时候B是不一定能马上知道的。
     
         3.  有序性-Ordering
         对于一个线程的执行代码而言,我们总是习惯性的认为代码的执行是从前往后依次执行的。但是在并发时,程序的执行就可能出现乱序。给人的直观感受就是:后面的代码先执行,前面的代码后执行。听起来很不可思议,这是由于程序在执行时,可能会进行指令重排,即在不影响串行语义的情况下对指令的顺序进行调整,以优化CPU的执行效率(指令重排可以保证串行语义一致,但没有办法保证多线程间的语义也一致)。关于指令重排,后面抽空再写专门的文章来说明。
         虽然java虚拟机和执行系统会对指令进行重排,但是还是有一些原则是指令重排不能违背的,即Happen-Before规则:
              A 程序顺序原则:一个线程内保证语义的串行性
              B volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性(抽空写一篇关于volatile的介绍)
              C 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
              D 传递性:A先于B,B先于C,则A必然先于C
              E 线程的start()方法先于它的每一个动作
              F 线程的所有操作先于线程的终结(Thread.join())
              G 线程的中断(interrupt())先于被中断线程的代码
              H 对象的构造函数执行、结束先于finalize()方法
     

    欢迎关注我的微信公众号(Sunnick,请扫码关注),随时留言交流~

  • 相关阅读:
    Rancher 2.1平台搭建及使用
    回归博客园
    CGI与FastCGI
    [转]1小时内打造你自己的PHP MVC框架
    MySQL学习随笔--通过实例理解merge ,temptable算法的差异
    MySQL学习随笔--视图
    使用onenote写博客园的方法
    手动配置wamp环境(1)--apache安装与基本操作
    文档兼容性定义,使ie按指定的版本解析
    JavaScript线程
  • 原文地址:https://www.cnblogs.com/sunnick/p/8979697.html
Copyright © 2011-2022 走看看