可见性:让一个线程对共享变量的修改,能够及时的被其他线程看到,java中首先想到的就是volatile

volatile关键字

Java内存模型中规定:

1.对某个volatile 字段的写操作happens-before 每个后续对该volatile 字段的读操作。

2.对volatile 变量v 的写入,与所有其他线程后续对v 的读同步。

volatile如何实现它的语义?

1.禁止缓存;volatile变量的访问控制符会加个ACC_VOLATILE

2.对volatile变量相关的指令不做重排序

共享变量定义

可以在线程之间共享的内存称为共享内存或堆内存。

所有实例字段、静态字段和数组元素都存储在堆内存中,这些字段和数组都是标题中提到的共享变量。

冲突:如果至少有一个访问是写操作,那么对同一个变量的两次访问是冲突的。

这些能被多个线程访问的共享变量是内存模型规范的对象。

线程操作定义

1.线程间操作指:一个程序执行的操作可被其他线程感知或被其他线程直接影响。

2.Java内存模型只描述线程间操作,不描述线程内操作,线程内操作按照线程内语义执行

操作间操作有:

read操作(一般读,即非volatile读)

write操作(一般写,即非volatile写)

volatile read

volatile write

Lock. (锁monitor)、Unlock

线程的第一个和最后一个操作

外部操作

所有线程间操作,都存在可见性问题,JMM需要对其进行规范

同步规则定义

1.对volatile变量v 的写入,与所有其他线程后续对v 的读同步

2.对于监视器m 的解锁与所有后续操作对于m 的加锁同步

3.对于每个属性写入默认值(0,false,null)与每个线程对其进行的操作同步

4.启动线程的操作与线程中的第一个操作同步

5.线程T2的最后操作与线程T1 发现线程T2 已经结束同步。(isAlive,join可以判断线程是否终结)

6.如果线程T1 中断了T2,那么线程T1 的中断操作与其他所有线程发现T2 被中断了同步通过抛出InterruptedException异常,或者调用Thread.interrupted或Thread.isInterrupted。

Happens-before先行发生原则

happens-before 关系用于描述两个有冲突的动作之间的顺序,如果一个action happendsbefore 另一个action,则第一个操作被第二个操作可见,JVM需要实现如下happens-before规则:

1.某个线程中的每个动作都happens-before 该线程中该动作后面的动作

2.某个管程上的unlock 动作happens-before 同一个管程上后续的lock 动作

3.对某个volatile 字段的写操作happens-before 每个后续对该volatile 字段的读操作

4.在某个线程对象上调用start()方法happens-before 被启动线程中的任意动作

5.如果在线程t1中成功执行了t2.join(),则t2中的所有操作对t1可见

6.如果某个动作a happens-before 动作b,且b happens-before 动作c,则有a happens-before c

7.当程序包含两个没有被happens-before 关系排序的冲突访问时,就称存在数据竞争

遵守了这个原则,也就意味着有些代码不能进行重排序,有些数据不能缓存

final在JMM中处理

final在该对象的构造函数中设置对象的字段,当线程看到该对象时,将始终看到该对象的final字段的正确构造版本。伪代码示例:f = new finalDemo(); 读取到的f.x一定最新,x为final字段。

如果在构造函数中设置字段后发生读取,则会看到该final字段分配的值,否则它将看到默认值;伪代码示例:public finalDemo(){ x = 1; y = x; }; y会等于1。

读取该共享对象的final成员变量之前,先要读取共享对象。伪代码示例: r = new ReferenceObj(); k = r.f; 这两个操作不能重排序。

通常被static final修饰的字段,不能被修改。然而System.in、System.out、System.err被static final修饰,却可以修改,遗留问题,必须允许通过set方法改变,我们将这些字段称为写保护,以区别于普通final字段。

Word Tearing字节处理

有些处理器(尤其是早期的Alphas 处理器)没有提供写单个字节的功能。在这样的处理器上更新byte 数组,若只是简单地读取整个内容,更新对应的字节,然后将整个内容再写回内存,将是不合法的。

这个问题有时候被称为“字分裂(word tearing)”,更新单个字节有难度的处理器,就需要寻求其它方式来解决问题。

因此,编程人员需要注意,尽量不要对byte[]中的元素进行重新赋值,更不要在多线程程序中这样做。

double和long的特殊处理

由于《Java语言规范》的原因,对非volatile 的double、long 的单次写操作是分两次来进行的,每次操作其中32位,这可能导致第一次写入后,读取的值是脏数据,第二次写完成后,才能读到正确值。

读写volatile 修饰的long、double是原子性的。

商业JVM不会存在这个问题,虽然规范没要求实现原子性,但是考虑到实际应用,大部分都实现了原子性。

《Java语言规范》中说道:建议程序员将共享的64位值(long、double)用volatile修饰或正确同步其程序以避免可能的复杂的情况。

总结:

1.深刻理解数据争用与冲突

2.深刻理解volatile关键字

3.final在多线程中的使用(为了保证线程始终看到对象字段的正确构造版本,需用final修饰该字段)

4.不要对线程共享的byte[]中的元素重新赋值,会带来数据一致性问题

5.最好用volatile修饰共享的64位值(long、double)

c++ 原子操作 赋值_多线程操作可见性相关推荐

  1. 两个子线程不冲突_多线程操作可见性

    可见性:让一个线程对共享变量的修改,能够及时的被其他线程看到,java中首先想到的就是volatile volatile关键字 Java内存模型中规定: 1.对某个volatile 字段的写操作hap ...

  2. c++ 原子操作 赋值_请问c++如何实现原子性操作?

    原子性,也就是要么全部做完,要么全部不做 在多进程(线程)访问资源时,能够确保所有其他的进程(线程)都不在同一时间内访问相同的资源.原子操作(atomic operation)是不需要同步,这是Jav ...

  3. c++ 原子操作 赋值_高级Java开发工程师带你走进原子操作,一篇文章搞清楚原子操作...

    原子特性: 原子是最小的粒子,不可再分 这并不是一个化学课,而是巧妙的借用了化学上的一个概念,即原子是最小的粒子,不可再分;原子操作也是不能再分的操作; 为了能把这个讲明白,下文基本都是大白话,其实J ...

  4. c++ 原子操作 赋值_原子操作原理

    1. 概念 原子操作是指不被打断的操作,即它是最小的执行单位.最简单的原子操作就是一条条的汇编指令(不包括一些伪指令,伪指令会被汇编器解释成多条汇编指令).在 linux 中原子操作对应的数据结构为 ...

  5. java多线程生产者与消费者案例_多线程操作实例——生产者与消费者

    面对多线程学习生产者与消费者是最基本的实例 对于java后端开发的人员必须要掌握,还有考研考试计算机操作系统的同鞋. 下面是三个实例对于生产者与消费者的的例子,层层递进,逐步解决问题. 问题:生产者- ...

  6. 多线程 转账_多线程编程不可错过——彻底理解volatile

    持续分享互联网一线研发技术,欢迎关注我. volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Ja ...

  7. java 多线程变量可见性_Java多线程:易变变量,事前关联和内存一致性

    java 多线程变量可见性 什么是volatile变量? volatile是Java中的关键字. 您不能将其用作变量或方法名称. 期. 我们什么时候应该使用它? 哈哈,对不起,没办法. 当我们在多线程 ...

  8. 第十章_多线程(2)_线程池原子性并发工具类

    目录 一.线程池 1 - 线程状态 2 - 线程池 3 - Executors线程池 二.Volatile 三.原子性 四.并发工具类 1 - 并发工具类-Hashtable 2 - 并发工具类-Co ...

  9. JAVA入门_多线程_邮局派发信件

    JAVA入门_多线程_邮局派发信件 Postman package cn.campsg.java.experiment.entity;public class Postman {private Str ...

最新文章

  1. Clang:LLVM 的 C 语言家族前端
  2. github设置添加SSH
  3. 晒一波程序员的工位,你中意哪一款?
  4. POSIX正则表达式 验证电子邮件地址
  5. 【学习笔记】6、标准数据类型—数字类型
  6. java正则匹配英文句号_「正则表达式」王国奇遇记
  7. html:(32):字体,字号,颜色
  8. mysql对本地文件的读取_Mysql 任意读取客户端文件
  9. @Controller @RestController
  10. SAP License:SAP中MM与财务的接口配置
  11. Redis内存相关知识
  12. 怎么在linux中运行gamess,桌面应用|在 Linux 中怎么运行 MS-DOS 游戏和程序
  13. windows10连接共享打印机报错:错误 0x00000709 解决方法
  14. 使用cisco2811c当pptp ***接入设备
  15. 如何在网上隐藏自己的IP地址(转)
  16. 泰勒公式矩阵形式_雅可比矩阵、黑森矩阵、泰勒展开式
  17. linux vi 应用
  18. hive sql 添加字段以及修改字段
  19. linux大容量硬盘 克隆到小硬盘_试玩免费硬盘克隆软件 再生龙 分区备份及恢复篇...
  20. 如何提取html 信息,从html中提取信息?

热门文章

  1. Idea下springboot+easyUI的下载与集成
  2. scala的字符串的方法(五)
  3. Maven问题-maven projects dependencies标红,但jar包事实上是没问题的
  4. Unity3d AR 增强现实技术列表(2016年3月31日更新)
  5. 将python程序打包为exe及一些问题
  6. 使用实时摄像头预览的iOS对象检测(六)
  7. PyTorch 1.7 发布:支持 CUDA 11、FFT 新 API、及 Windows 分布式训练
  8. 使用Jenkins在Azure Web App上进行ASP.NET Core应用程序的持续集成和部署(CI/CD)–第2天
  9. CSS从大图中抠取小图完整教程(background-position应用)【转】
  10. 计算机工作应用工作简历,计算机应用专业工作简历范文