热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

并发编程笔记二:java的内存模型

内容多有疏漏,有问题欢迎提出目录java内存模型的概念原子性(Atomicity)可见性(Visibility࿰

内容多有疏漏,有问题欢迎提出


目录


  1. java内存模型的概念
  2. 原子性(Atomicity)
  3. 可见性(Visibility)
  4. 有序性(Ordering)
  5. 总结

java内存模型的概念

java并发程序开发比串行程序开发复杂的多,其中重要的一点就是要保证数据的正确性。对于串行来讲,输入是1,输出一定是1,这个很好保证,但是对于并行开发来讲,中间如果没有做好数据在多线程中的控制,很有可能导致输入是,输出可能是1,也可能是111。java内存模型(JMM)就是为了保证数据在多线程中正确性的一种协议。

 

其中,JMM最关键的技术点都是围绕着多线程的原则性、可见性和有序性来建立。下面,我们重点来讨论多线程中的这三大特性。

 

原子性(Atomicity)

原子性指一个操作是不可中断的,即要么全部执行成功要么全部执行失败,不接受一半成功一半失败的情况。


int a = 10; //1

a++; //2


以上两种场景,只有第一种是原则性操作,第二种虽然看起来是一步执行完成,但是实际上他执行了


  1. 读取a的值
  2. 对a进行加1的操作
  3. 把加1后的值赋给变量

在开发中,常用的保证原子性的操作即是加上sychronized的锁,加锁之后的效果就是把锁住的类、方法、对象作为一个整体,在该模块处理完之前,不允许其他操作调用该模块。

另外一种锁--volatile只能可见性和有序性,不能保证原子性,所以在下面例子中,使用volatile进行数据一致性的操作是有问题的:


public class VolatileExample {private static volatile int counter &#61; 0;public static void main(String[] args) {for (int i &#61; 0; i <10; i&#43;&#43;) {Thread thread &#61; new Thread(new Runnable() {&#64;Overridepublic void run() {for (int i &#61; 0; i <10000; i&#43;&#43;)counter&#43;&#43;;}});thread.start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(counter);}
}​

如果volatile可以保证原子性的话&#xff0c;实际输出结果应该是100000&#xff0c;但是真实的结果远小于100000。

然而想要保证上面例子的结果输出正确的话&#xff0c;我们可以做这样的修改&#xff1a;

public class VolatileExample {private static volatile int counter &#61; 0;public static void main(String[] args) {for (int i &#61; 0; i <10; i&#43;&#43;) {Thread thread &#61; new Thread(new Runnable() {&#64;Overridepublic void run() {for (int i &#61; 0; i <10000; i&#43;&#43;)//在counter&#43;&#43;操作时加上synchronized锁synchronized (VolatileExample.class){counter&#43;&#43;;}}});thread.start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(counter);}
}

或者使用AtomicInteger这样线程安全的类进行变量赋值的操作。

import java.util.concurrent.atomic.AtomicInteger;public class Atomicity {//使用保证的原子性的AtomicInteger类进行counter变量的修改操作static AtomicInteger counter &#61; new AtomicInteger();private static void count() {Atomicity atomicity &#61; new Atomicity();for (int i &#61; 0; i <10; i&#43;&#43;) {Thread thread &#61; new Thread(new Runnable() {&#64;Overridepublic void run() {for (int i &#61; 0; i <10000; i&#43;&#43;)//addAndGet是线程安全的修改方法counter.addAndGet(1);}});thread.start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicity.counter);}public static void main(String[] args) {count();}
}

这样写的话&#xff0c;实际的输出结果就是100000。

可见性&#xff08;Visibility&#xff09;

可见性是指当一个线程修改了某一个共享变量的值时&#xff0c;其他的线程是否能够立即知道这个修改。

即当CPU1一个线程修改了一个全局变量a&#xff0c;并将其缓存在cache中或者寄存器里&#xff0c;在此同时CPU2上的某一线程也对全局变量a进行修改&#xff0c;也将其及存到cache或寄存器里&#xff0c;这样&#xff0c;两个线程对于全局变量a的值可能存在不一样的情况&#xff0c;从而导致接下来的数据处理可能会异常。

对此&#xff0c;sychronized和volatile关键字都可以保证操作的可见性&#xff0c;即当某一全局变量一旦被修改&#xff0c;就会立刻被刷新到主内存中去&#xff0c;保证多线程中数据的一致性。

 

有序性&#xff08;Ordering&#xff09;

在多线程执行过程中&#xff0c;一般理解代码会按顺序从前到后依次执行&#xff0c;但是出于某种原因&#xff0c;在某些情况下&#xff0c;程序会对指令重新排序&#xff0c;导致程序操作结果异常。在单一线程中&#xff0c;指令执行的顺序一定是一致的&#xff08;否则程序无法正常工作&#xff09;&#xff0c;只有在并行的程序中&#xff0c;才会发生指令重排序的情况。但是总结性的来讲&#xff0c;指令的重排序不是无意义的&#xff0c;他的目的是为了尽量少的中断流水线&#xff0c;提高程序的性能。

对于哪些指令不能重拍&#xff0c;也有既定的规则&#xff0c;即Happen-Before规则&#xff1a;


  • 程序顺序原则&#xff1a;一个县城内保证语义的串行性&#xff1b;
  • volatile规则&#xff1a;volatile变量的写咸鱼度发生&#xff0c;这保证了volatile变量的可见性&#xff1b;
  • 锁规则&#xff1a;解锁&#xff08;unlock&#xff09;必然发生在随后加锁&#xff08;lock&#xff09;之前&#xff1b;
  • 传递性&#xff1a;A先于B&#xff0c;B先于C&#xff0c;那么A必然先于C&#xff1b;
  • 线程的start&#xff08;&#xff09;方法先与他的每一个动作&#xff1b;
  • 线程的所有操作先于线程的终结&#xff08;Thread.join()&#xff09;&#xff1b;
  • 线程的中断&#xff08;interrupt()&#xff09;先于被中断线程的代码&#xff1b;
  • 对象的构造函数的执行&#xff0c;结束先于finalize()方法&#xff1b;

 

总结

本章说明了了java内存模型&#xff08;JMM&#xff09;是保证多线程中数据正确性的基础协议&#xff0c;并对多线程中原子性、可见性、有序性这三大特性进行了分析。下一章的内容&#xff0c;我们会从java线程讲起&#xff0c;阐述线程从创建到终止的一些列操作。

 

 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
author-avatar
老男孩标兄_164
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有