`

Volatile与sychronized

    博客分类:
  • Java
 
阅读更多

    在使用 volatile 关键字时要慎 重,并不是只要简单类型变量使用 volatile 修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如 n=n+1 n++ 等, volatile 关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如 n = m + 1 ,这个就是原级别的。所以在使用 volatile 关键时一定要谨慎,如果自己没有把握,可以使用 synchronized 来代替 volatile

Volatile: 用在多线程,同步变量。 线程为了提高效率,将某成员变量 ( A) 拷贝了一份(如 B ),线程中对 A 的访问其实访问的是 B 。只在某些动作时才进行 A B 的同步。因此存在 A B 不一致的情况。 volatile 就是用来避免这种情况的。 volatile 告诉 jvm 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的 A)

Synchronized: 同步方法或变量的同时也锁定了类

 

 

深入了解 synchronized 及对象锁

2008-09-09 10:361 , Synchronized 锁定的是对象而非函数或代码。

2 , 每个 Object 只有一把锁 (Lock) 与之关联,当进行到 Synchronized 语句或函数的时候,这把锁就会被当前的线程( thread )拿走,其他的( thread )再去访问的时候拿不到锁就被暂停了

3, 只有当 Synchronized 的是同一个对象的才是线程安全的( thread-safe

:

    1) public Synchronized void method1 : 锁住的是该对象 , 类的其中一个实例 , 当该对象 ( 仅仅是这一个对象 ) 在不同线程中执行这个同步方法时 , 线程之间会形成互斥 . 达到同步效果 , 但如果不同线程同时对该类的不同对象执行这个同步方法时 , 则线程之间不会形成互斥 , 因为他们拥有的是不同的锁 .

    2) Synchronized(this){ //TODO } 同一

 

    3) public Synchronizedstatic void method3 : 锁住的是该类 , 当所有该类的对象 ( 多个对象 ) 在不同线程中调用这个 static 同步方法时 , 线程之间会形成互斥 , 达到同步效果 , 但如果多个线程同时调用 method1 , method3, 则不会引互斥 , 具体讲看最后讲解 .

    4) Synchronized(Test.class){ //TODo} 同三

 

    5) synchronized(o) {} 这里面的 o 可以是一个任何 Object 对象或数组 , 并不一定是它本身对象或者类 , 谁拥有 o 这个锁 , 谁就能够操作该块程序代码 .

 

这里面 1) 2) 是线程安全的 , 1) 3) , 2) 3) 他们所拥有的锁不一样 , 故不是同步的 , 不是线程安全的 .

 

 

最后 , synchronized 所同步的代码应该尽量少 . 如果没有必要同步的就不要列为其中

     联想到数据库的并发控制

假如有如下操作

    1) 从数据库中读取数据

    2) 修改数据

    3) 提交数据

解决方案一

1) 读取数据

synchronized(XXX)

{

    2) 修改数据

    3) 提交数据

解决方案二

synchronized(XXX)

{

    1) 读取数据

    2) 修改数据

    3) 提交数据

}

 

解决方案三

synchronized(XXX)

{

     3) 提交数据

}

 

这里面到底用哪一种方案视具体情况而定 , 要注意的是 synchronized( 同步 ) 的代价 , 开销是很大的 .

 

 

 

volatile 关键字有什么用?

  恐怕比较一下 volatile synchronized 的不同是最容易解释清楚的。 volatile 是变量修饰符,而 synchronized 则作用于一段代码或方法;看如下三句 get 代码:

int i1;                          int geti1() {return i1;}

volatile int i2;              int geti2() {return i2;}

int i3; synchronized     int geti3() {return i3;}

 

   geti1() 得到存储在当前线程中 i1 的数值。多个线程有多个 i1 变量拷贝,而且这些 i1 之间可以互不相同。换句话说,另一个线程可能已经改变了它线程内的 i1 值,而这个值可以和当前线程中的 i1 值不相同。事实上, Java 有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的 i1 值是 1 ,线程 1 里的 i1 值是 2 ,线程 2 里的 i1 值是 3 ——这在线程 1 和线程 2 都改变了它们各自的 i1 值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。

  而 geti2() 得到的是“主”内存区域的 i2 数值。用 volatile 修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经 volatile 修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的, volatile 修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。

  既然 volatile 关键字已经实现了线程间数据同步,又要 synchronized 干什么呢?呵呵,它们之间有两点不同。首先, synchronized 获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是, synchronized 也同步内存:事实上, synchronized 在“主”内存区域同步整个线程的内存。因此,执行 geti3() 方法做了如下几步:

1. 线程请求获得监视 this 对象的对象锁(假设未被锁,否则线程等待直到锁释放)

2. 线程内存的数据被消除,从“主”内存区域中读入( Java 虚拟机能优化此步。。。 [ 后面的不知道怎么表达 , ]

3. 代码块被执行

4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过 geti3() 方法不会改变变量值)

5. 线程释放监视 this 对象的对象锁

  因此 volatile 只是在线程内存和“主”内存间同步某个变量的值,而 synchronized 通过锁定和解锁某个监视器同步所有变量的值。显然 synchronized 要比 volatile 消耗更多资源。

分享到:
评论

相关推荐

    java并发编程面试题分享给需要的同学.docx

    sychronized和Lock(ReentrantLock)之间的区别? sychoronized的自旋锁、偏向锁、轻量级锁、重量级锁、分别介绍和联系 threadLocal会发生内存泄漏吗?谈谈你对threadLocal的理解 为什么会发生内存泄漏? 对...

    java核心知识点整理.pdf

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    强化学习——电网运营和维护的强化学习,用于电网优化运营和维护Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    cmd-bat-批处理-脚本-MakeToolWindow.zip

    cmd-bat-批处理-脚本-MakeToolWindow.zip

    “华为杯”第十八届中国研究生数学建模竞赛参赛论文

    “华为杯”第十八届中国研究生数学建模竞赛是一项全国性赛事,致力于提升研究生的数学建模与创新实践能力。数学建模是将实际问题转化为数学模型,并运用数学方法求解以解决实际问题的科学方法。该竞赛为参赛者提供了展示学术水平和团队协作精神的平台。 论文模板通常包含以下内容:封面需涵盖比赛名称、学校参赛队号、队员姓名以及“华为杯”和中国研究生创新实践系列大赛的标志;摘要部分应简洁明了地概括研究工作,包括研究问题、方法、主要结果和结论,使读者无需阅读全文即可了解核心内容;目录则列出各章节标题,便于读者快速查找;问题重述部分需详细重新阐述比赛中的实际问题,涵盖背景、原因及重要性;问题分析部分要深入探讨每个问题的内在联系与解决思路,分析各个子问题的特点、难点及可能的解决方案;模型假设与符号说明部分需列出合理假设以简化问题,并清晰定义模型中的变量和符号;模型建立与求解部分是核心,详细阐述将实际问题转化为数学模型的过程,以及采用的数学工具和求解步骤;结果验证与讨论部分展示模型求解结果,评估模型的有效性和局限性,并对结果进行解释;结论部分总结研究工作,强调模型的意义和对未来研究的建议;参考文献部分列出引用文献,遵循规范格式。 在准备竞赛论文时,参赛者需注重逻辑清晰、论述严谨,确保模型科学实用。良好的团队协作和时间管理也是成功的关键。通过竞赛,研究生们不仅锻炼了数学应用能力,还提升了团队合作、问题解决和科研写作能力。

    一个检测俯卧撑和下蹲的检测系统

    希望这会对大家有用,共同发挥互联网精神!

    用于分析和表示神经动脉血流的MATLAB模型.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    cmd-bat-批处理-脚本-Run python script.zip

    cmd-bat-批处理-脚本-Run python script.zip

    基于MatlabSimulink的UKFEKF路面附着系数估计及仿真分析 MatlabSimulink

    内容概要:本文详细介绍了利用Matlab/Simulink平台,通过无迹扩展卡尔曼滤波(UKF/EKF)进行路面附着系数估计的方法及其仿真功能。文中首先阐述了Dugoff轮胎模型的构建方法,强调了避免代数环的重要性,并提供了具体的模块连接方式。接着,描述了7自由度整车模型的搭建步骤,特别是质心加速度和轮速之间的耦合关系。最后,深入探讨了UKF和EKF滤波器的配置细节,包括状态变量选择、观测值设定以及协方差矩阵的初始化等关键参数调整。仿真结果显示,在80km/h的速度下,UKF相比EKF的均方误差降低了18%,但CPU耗时增加了40%。 适合人群:从事车辆控制系统研究的专业人士,尤其是对卡尔曼滤波有一定了解的研究人员和技术人员。 使用场景及目标:适用于需要精确估计路面附着系数的应用场合,如汽车电子稳定程序(ESP)的设计与优化。通过提高附着系数估计的准确性,可以有效提升车辆行驶的安全性和稳定性。 其他说明:文章不仅提供了理论指导,还给出了实际操作的具体步骤和注意事项,帮助读者更好地理解和应用相关技术。

    实体建模技术研究进展.zip

    实体建模技术研究进展.zip

    基于4G通信的高负载电动汽车远程监控平台软件设计与开发.zip

    基于4G通信的高负载电动汽车远程监控平台软件设计与开发.zip

    IMG_20250521_201207.jpg

    IMG_20250521_201207.jpg

    cmd-bat-批处理-脚本-数学-isInteger.zip

    cmd-bat-批处理-脚本-数学-isInteger.zip

    基于改进DeepLabv3+的高分辨率遥感影像屋顶提取方法.pdf

    基于改进DeepLabv3+的高分辨率遥感影像屋顶提取方法.pdf

    cmd-bat-批处理-脚本-post-install.zip

    cmd-bat-批处理-脚本-post-install.zip

    基于遗传算法优化的BP神经网络预测模型代码及注释

    遗传算法优化BP神经网络(GABP)是一种结合了遗传算法(GA)和BP神经网络的优化预测方法。BP神经网络是一种多层前馈神经网络,常用于模式识别和预测问题,但其容易陷入局部最优。而遗传算法是一种模拟自然选择和遗传机制的全局优化方法,能够有效避免局部最优 。GABP算法通过遗传算法优化BP神经网络的权重和阈值,从而提高网络的学习效率和预测精度 。 种群:遗传算法中个体的集合,每个个体代表一种可能的解决方案。 编码:将解决方案转化为适合遗传操作的形式,如二进制编码。 适应度函数:用于评估个体解的质量,通常与目标函数相反,目标函数值越小,适应度越高。 选择:根据适应度保留优秀个体,常见方法有轮盘赌选择、锦标赛选择等。 交叉:两个父代个体交换部分基因生成子代。 变异:随机改变个体的部分基因,增加种群多样性。 终止条件:当迭代次数或适应度阈值达到预设值时停止算法 。 初始化种群:随机生成一组神经网络参数(权重和阈值)作为初始种群 。 计算适应度:使用神经网络模型进行训练和预测,根据预测误差计算适应度 。 选择操作:根据适应度选择优秀个体 。 交叉操作:对选择的个体进行交叉,生成新的子代个体 。 变异操作:对子代进行随机变异 。 替换操作:用新生成的子代替换掉一部分旧种群 。 重复步骤2-6,直到满足终止条件 。 适应度函数通常以预测误差为基础,误差越小,适应度越高。常用的误差指标包括均方根误差(RMSE)或平均绝对误差(MAE)等 。 GABP代码中包含了适应度函数的定义、种群的生成、选择、交叉、变异以及训练过程。代码注释详尽,便于理解每个步骤的作用 。 GABP算法适用于多种领域,如时间序列预测、经济预测、工程问题的优化等。它特别适合解决多峰优化问题,能够有效提高预测的准确性和稳定性 。

    太阳高度角和方位角建模及核桃树阴影变化分析.pdf

    太阳高度角和方位角建模及核桃树阴影变化分析.pdf

    cmd-bat-批处理-脚本-param2.zip

    cmd-bat-批处理-脚本-param2.zip

    前端开发Uniapp日期时间选择器:实现分钟动态步长设置

    Uniapp原生适配日期时间选择器,可动态设置分钟显示间隔

Global site tag (gtag.js) - Google Analytics