>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 21687 个阅读者 刷新本主题
 * 贴子主题:  volatile 与 synchronized 详解 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-02-06 23:34:40     消息  查看  搜索  好友  邮件  复制  引用

          
                                                              
Java支持多个线程同时访问一个对象或者对象的成员变量,由于每个线程可以拥有这个变量的拷贝(虽然对象以及成员变量分配的内存是在共享内存中的,但是每个执行的线程还是可以拥有一份拷贝,这样做的目的是加速程序的执行,这是现代多核处理器的一个显著特性),所以程序在执行过程中,一个线程看到的变量并不一定是最新的。

volatile

volatile的应用

在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,<mark>volatile 是一个轻量级的 synchronized ,它在多处理器开发中保证了共享变量的 可见性</mark>。可见性的意思是当一个线程修改一个共享变量的时候,另一个线程能读取到这个共享变量被修改后的值。如果 volatile 使用恰当的话,它比 synchronized 的使用和执行成本更低,因为 volatile 不会引起线程上下文的切换和调度

volatile的定义与实现原理

Java 编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致性地更新,线程应该确保通过排他锁来单独获取这个变量。Java 提供的 volatile 在某些情况下比锁要方便。如果一个字段被声明为 volatile,那么Java模型确保所有的线程看到这个变量的值是一致的

作用:

volatile关键字用作成员变量的修饰符,以强制单个线程每次从共享内存中重新读取变量的值

访问。 此外,各个线程被迫将更改写回到共享记忆一旦发生。 这样,两个不同的线程总是看到相同的在任何特定时间成员变量的值

volatile的两条实现原则

  • Lock 前缀指令会引起处理器缓存回写到内存
  • 一个处理器的缓存回写到内存会导致其他的处理器的缓存无效

synchronized

synchronized 关键字可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性

synchronized的实现原理与应用

在多线程并发编程中 synchronized 一直是元老级的角色,很多人都会直呼它为重量级锁。但是,随着 Java SE 1.6 对 synchronized 进行了各种优化之后,有些情况下synchronized 并没有那么重了

synchronized如何实现同步?

synchronized 实现同步的基础:Java中的每一个对象都可以作为锁。具体的表现形式有以下三种:
  • 对于普通同步方法,锁是当前实例对象
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是 synchronized 括号里配置的对象
当一个线程试图访问同步代码块时,必须先获取到锁,退出或抛出异常时必须释放锁

volatile 与 synchronized 的区别?

volatile synchronized
修饰 只能用于修饰变量 可以用于修饰方法、代码块
线程阻塞 不会发生线程阻塞 会发生阻塞
原子性 不能保证变量的原子性 可以保证变量原子性
可见性 可以保证变量在线程之间访问资源的可见性 可以间接保证可见性,因为它会将私有内存中和公共内存中的数据做同步
同步性 能保证变量在私有内存和主内存间的同步 synchronize是多线程之间访问资源的同步性
  • volatile 是线程同步的轻量级实现,所以 volatile 的性能要比 synchronize 好;随着jdk技术的发展,synchronize 在执行效率上会得到较大提升,所以 synchronize 在项目过程中还是较为常见的
  • 对于 volatile 修饰的变量,可以解决变量读时可见性问题,无法保证原子性。对于多线程访问同一个实例变量还是需要加锁同步
在多线程定义中,volatile 关键字主要是在属性上使用的,表示此属性为直接数据操作,而不进行副本的拷贝处理。这样的话在一些书上就将其错误的理解为同步属性了。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小    

  package com .java .springtest .test ;

/**
* @author Woo_home
* @create by 2020/1/20
*/

public  class  ThreadDemo  {
     public  static  void  main (String [ ] args )  throws Exception {
        ThreadShop shopA  =  new  ThreadShop ( ) ;
        ThreadShop shopB  =  new  ThreadShop ( ) ;
        ThreadShop shopC  =  new  ThreadShop ( ) ;
         new  Thread (shopA , "A 店铺" ) . start ( ) ;
         new  Thread (shopB , "B 店铺" ) . start ( ) ;
         new  Thread (shopC , "C 店铺" ) . start ( ) ;
     }
}

class  ThreadShop  implements  Runnable  {

     private  volatile  int product  =  5 ;  // 直接内存操作

     @Override
     public  void  run ( )  {
         synchronized  ( this )  {
             while  ( this .product  >  0 )  {
                 try  {
                    Thread . sleep ( 100 ) ;
                 } catch  ( InterruptedException e )  {
                    e . printStackTrace ( ) ;
                 }
                System .out . println (Thread . currentThread ( ) . getName ( )  +  "商品处理,product = "  +  this .product -- ) ;
             }
         }
     }
}

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

     面试题: 请解释 volatile 与 synchronized 的区别?
  • volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile 仅能使用在变量级别;synchronized 则可以使用在变量、方法、和类级别
  • volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证变量的修改可见性和原子性
  • volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
  • volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化
----------------------------
原文链接:https://blog.csdn.net/Woo_home/article/details/102651639

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-02-24 12:50:09 重新编辑]
  Java面向对象编程-->输入与输出(下)
  JavaWeb开发-->JSP技术详解(Ⅱ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->非阻塞通信
  精通Spring-->Vue CLI脚手架工具
  Vue3开发-->创建综合购物网站应用
  TCP、UDP及Socket代码示例
  Java Proxy用法: 让我们创建一个API代理器
  Java的对象的拷贝方式集合
  Eclipse和MyEclipse的区别
  Java并发编程之验证volatile不能保证原子性
  Java设计模式:抽象工厂模式
  java常见的几种调用机制:同步调用,异步调用,回调
  Eclipse使用指南:快速修复功能
  Eclipse使用指南:创建Java项目的步骤
  Java设计模式:享元模式
  Java入门实用代码:线程状态监测
  Java入门实用代码: List 列表中元素的替换
  Java入门实用代码: 集合中添加元素
  Java 入门实用代码:设置文件只读
  Java入门实用代码:修改文件最后的修改日期
  更多...
 IPIP: 已设置保密
树形列表:   
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。