线程安全中的原子性,有序性和可见性

news2024/11/16 17:44:52

对于Java并发编程,一般来说有以下的关注点:

  1. 线程安全性,正确性。

  2. 线程的活跃性(死锁,活锁)

  3. 性能

其中线程的安全性问题是首要解决的问题,线程不安全,运行出来的结果和预期不一致,那就连基本要求都没达到了。

保证线程的安全性问题,本质上就是保证线程同步,实际上就是线程之间的通信问题。我们知道,在操作系统中线程通信有以下几种方式:

  1. 信号量

  2. 信号

  3. 管道

  4. 共享内存

  5. 消息队列

  6. socket

java中线程通信主要使用共享内存的方式。共享内存的通信方式首先要关注的就是可见性和有序性。而原子性操作一般都是必要的,所以主要关注这三个问题。

1.原子性

原子性是指操作是不可分的。其表现在于对于共享变量的某些操作,应该是不可分的,必须连续完成。例如a++,对于共享变量a的操作,实际上会执行三个步骤:

  1. 读取变量a的值

  2. a的值+1

  3. 将值赋予变量a 。

这三个操作中任何一个操作过程中,a的值被人篡改,那么都会出现我们不希望出现的结果。所以我们必须保证这是原子性的。Java中的锁的机制解决了原子性的问题。

2.可见性

可见性是值一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的。

为什么会出现这种问题呢?

我们知道,java线程通信是通过共享内存的方式进行通信的,而我们又知道,为了加快执行的速度,线程一般是不会直接操作内存的,而是操作缓存。

java线程内存模型:

实际上,线程操作的是自己的工作内存,而不会直接操作主内存。如果线程对变量的操作没有刷写会主内存的话,仅仅改变了自己的工作内存的变量的副本,那么对于其他线程来说是不可见的。而如果另一个变量没有读取主内存中的新的值,而是使用旧的值的话,同样的也可以列为不可见。

对于jvm来说,主内存是所有线程共享的java堆,而工作内存中的共享变量的副本是从主内存拷贝过去的,是线程私有的局部变量,位于java栈中。

那么我们怎么知道什么时候工作内存的变量会刷写到主内存当中呢?

这就涉及到java的happens-before关系了。

在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

这个人的博客写的不错:http://ifeve.com/easy-happens-before/。

简单来说,只要满足了happens-before关系,那么他们就是可见的。

例如:

线程A中执行i=1,线程B中执行j=i。如果线程A的操作和线程B的操作满足happens-before关系,那么j就一定等于1,否则j的值就是不确定的。

happens-before关系如下:

  1. 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

  2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;

  3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

  4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

  5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

  6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

  7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

  8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

从上面的happens-before规则,显然,一般只需要使用volatile关键字,或者使用锁的机制,就能实现内存的可见性了。

3.有序性

有序性是指程序在执行的时候,程序的代码执行顺序和语句的顺序是一致的。

为什么会出现不一致的情况呢?

这是由于重排序的缘故。

在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

举个例子:

线程A:

context = loadContext();    
inited = true;    

线程B:

while(!inited ){
 sleep
}
doSomethingwithconfig(context);

如果线程A发生了重排序:

inited = true;    
context = loadContext(); 

那么线程B就会拿到一个未初始化的content去配置,从而引起错误。

因为这个重排序对于线程A来说是不会影响线程A的正确性的,而如果loadContext()方法被阻塞了,为了增加Cpu的利用率,这个重排序是可能的。

如果要防止重排序,需要使用volatile关键字,volatile关键字可以保证变量的操作是不会被重排序的。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机的发展史与计算机硬件组成

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.计算机的发展史 1.计算机发展的四个时代 二.计算机硬件组成 …

#D. Journey之二

一,题目Description给出一棵树N个点及数字K接下来N-1行描述有关边的开始点,结束点.保证图中不会有环接下来K个数字,代表你要走过的点的编号.当然你可以自己选择出发点及行进的路线不一定按给定编号顺序前行,求走过的最短距离。FormatInput第一行给出N,K。…

工具及方法 - 文件正在被使用,无法改名或删除怎么办

有时我们想重命名或删除一个文件时,会提示错误,提示文件被占用。 比如提示:“The action can’t be completed because the folder is open in another program“。 或者: 或者: 就是因为有进程锁定(process is lock…

004-Ensp-实验-配置DNS

实验要求 1. 在PC2中Ping www.pc1.com 可以访问到PC2 2. 在PC1中Ping www.pc2.com 可以访问到PC2 网络结构 实验步骤 #需要开启DHCP [Huawei]interface g0/0/0 [Huawei-GigabitEthernet0/0/0]dhcp server dns-list 192.168.0.100 测试

人工智能:数字图像类型和常见格式介绍

❤️作者主页:IT技术分享社区 ❤️作者简介:大家好,我是IT技术分享社区的博主,从事C#、Java开发九年,对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉: 数据库领域优质创作者🏆&#x…

【C语言】-深入内存带你看数据的存储

🎇作者:小树苗渴望变成参天大树 🎉 作者宣言:认真写好每一篇博客 🎊作者gitee:link 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 数据的存储🧨 前言✨一、数据类型…

007-Ensp-实验-配置静态路由

实验要求 PC1 可以访问到 PC2 网络结构 实验步骤 1. AR1 G0/0/0 - G0/0/1 配置IP 2. AR2 G0/0/0 - G0/0/1 配置IP 3. PC1 PC2 配置IP/GateWay 4. AR1 配置静态路由表 ip route-static 192.168.1.0 255.255.255.0 192.168.5.2 5. AR2 配置静态路由表 ip route-static 19…

Linux虚拟机克隆后网卡名从eth0变成eth1

文章目录一 系统环境二 问题发现三 解决过程一 系统环境 原本被克隆的主机是 rhel6.9 的操作系统。 二 问题发现 对 rhel6.9 的主机克隆后,发现无法SSH远程连接,从而发现可能是网卡的问题需要解决。 首先检查网卡服务是否启动 发现network服务是正常运…

java在线视频播放系统视频网站影视网站电影电视剧播放网站源码

简介 ssm开发的视频网站。本项目主要包括了视频展示和查询功能,用户中心,积分管理,管理员管理等功能。 演示视频 https://www.bilibili.com/video/BV1tT4y1N7t8/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 技…

【408篇】C语言笔记-第二十二章(文件的操作)

文章目录第一节:文件操作原理1. C文件概述2. 文件指针介绍第二节:文件的打开与关闭1. 文件打开与关闭常用函数2. 代码实战第三节:文件的读写1. fread函数与fwrite函数2. fgets函数与fputs函数第四节:文件位置指针偏移1. fseek函数…

2023-01-04 clickhouse-编译、开发、测试

https://bohutang.me/2020/06/05/clickhouse-and-friends-development/ 一次偶然的机会,和ClickHouse团队做了一次线下沟通,Alexey提到ClickHouse的设计哲学: The product must solve actual problemAnd do it better than others 用工程思维解决商业问…

人工智能期末试卷

一、简答题(共 24 分) 若将人看成一个信息处理系统,1) 人的智能具有哪些特征?2) 举例说明哪一特征是最重要的并 3) 阐述其与实现通用人工智能的关系。(要求:2、3 小问一定用自己的语言作答!)(8 …

javaweb课程设计-基于SSM框架的疫情数据统计分析系统源码+数据库,可以进行疫情数据录入、疫情数据查询、图表展示

疫情数据统计分析系统 完整代码下载地址:基于SSM框架的疫情数据统计分析系统源码数据库 介绍 疫情数据统计分析系统是一个基于SSM框架的网页端系统,项目中实现的功能如下:用户访问网站可以浏览全国疫情的图表信息,管理员登录后…

P1229 遍历问题

题目描述 我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给定…

人工智能知识图谱研究

1、研究背景及意义 随着互联网技术的发展以及大数据、人工智能等新科技时代的来临,我国高校教育改革、高校人才培养也面临着新的机遇与挑战。一方面,为了实现国家战略、支撑快速发展的新经济,需要高校变革发展培养新型人才,满足社…

Au 效果器详解:自适应降噪

Au菜单:效果/降噪/恢复/自适应降噪Adaptive Noise Reduction自适应降噪 Adaptive Noise Reduction可快速去除变化的宽频噪声,如背景声音、隆隆声、风声等。此效果实时起作用,并可在多轨编辑器中使用。相对于标准降噪效果,自适应降…

cc1-7分析-2

cc2 cc2和cc4呢其实区别也不是很大,最后的rce的方式也都是一样的。区别在哪呢,之前我们说过TemplatesImpl.newTransformer是可以直接进行rce的,cc2就是通过 InvokerTransformer直接去调用TemplatesImpl.newTransformer,不走Insta…

Kubernetes(3)- Serivce详解

第七章 Service详解 本章节主要介绍kubernetes的流量负载组件:Service和Ingress。 Service介绍 ​ 在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着…

【数据结构】带头双向循环链表的实现

目录 一、什么是带头双向循环链表 二、带头双向循环链表的实现 1、创建一个动态头结点 2、双向链表初始化 3、打印双向链表 4、双向链表尾插 5、双向链表尾删 6、双向链表头插 7、双向链表头删 8、双向链表查找 9、双向链表在pos的前面进行插入x 10、双向链表删除pos位置的结点…

植物大战僵尸:寻找葵花生产速度

通过CE修改器遍历出控制太阳花吐出阳光的时间变量,太阳花吐出阳光是由一个定时器控制的,首先我们找到第一个太阳花的基址与偏移,然后找出第二个太阳花的动态地址,并通过公式计算得到太阳花结构长度的相对偏移,最后我们…