volatile关键字和synchronize关键字

在java多线程中估计会经常见到volatile和synchronize这两个关键字,今天做个笔记记录下两个关键字的区别:

synchronize:

synchronize关键字我们遇到的概率很大(虽然现在基本上都用重用锁ReentrantLock),它可以去修饰方法或者代码块,可以用一个对象去做锁或者用类class做锁,也就是对象锁和类锁,最好不要使用常量做锁的关键字例如字符串,这样很可能会造成锁的不释放问题(常量池只有一个引用),并且加锁代码块里面不要修改这个锁,不然锁就会失效,其他方法会获得锁了 (对象属性发生改变了不会影响,只是引用),他会让一堆线程对一个资源进行抢占,抢占到的线程就可以执行,没抢占到的线程就会等待,直到占用资源的线程执行完成(互斥性),它具有原子性。

volatile:

volatile关键字,它不具有原子性,它只是对其他线程具有可见性。


其中原子性和可见性可以拿一个很经典的线程安全的例子来说明(多个线程对同一个数字类型变量进行加1),当有多个线程操作同一个共享变量的时候,java中有一个逻辑上面的内存模型(JMM)。每个线程都是独立的且他们都有一个工作内存和一个主内存(共享内存),为了增加运行速度,jdk1.5之后 执行线程的时候会单独分配内存空间,会将主内存的副本copy到自己的工作内存空间中,所以当多个线程对同一个共享变量进行加1的操作就会造成线程安全问题,比如3个线程对初始值等于0的i进行加1操作,很有可能三个线程将i=0这个初始值都拿到了自己的工作内存中,然后进行加1,然后刷新到主内存中,得到最后的结果可能是1,当然也可能是2或者3,这样就不具有原子性了。当对操作用synchronize关键字来修饰的话,就只运行从主内存进行操作,并且操作是互斥的,一个线程对i进行加1,其他线程只有等待,当该线程执行完成后,其他线程才能执行这个方法,这就具有原子性了。 而如果加了volatile只是让变量具有了可见性,该关键字通过CPU的内存屏障指令让所有线程操作都在主内存中进行,这样每个线程都能获取到最新的值,但是可能会有多个线程同时对这个i进行加1,所以volatile只是有可见性不具有原子性。(当然这种情况可以使用Atomic系列的对象,他是原子性的

其中上面JMM只是一个逻辑模型,他可能发生计算机物理内存模型的寄存器内、高速缓存(cpu一级缓存、二级缓存等)、内存条任意一个里面。

现在的计算机都是多核心多线程的所以为了提高性能而采取乱序执行,所以才有了CPU的内存屏障指令 ,就是让内存屏障之前的所有写操作都要写入内存中。

其中synchronize和volatile关键字能防止指令的重排序(还包括比如join或者CountDownLatch等等都能防止指令重排序)

重排序就是为了程序的执行效率而产生的,之前也说了现在的电脑都是多核心且多线程的,如果有两个操作:

(1) String str = read(磁盘)
(2) String a = 1+1;

在上面的两个操作中,(1)需要去读取磁盘东西的非常耗时,而(2)操作很快,如果没有指令重排序的机制,那么(2)操作只能等(1)操作执行完成后才能执行,这样就降低了计算机的性能(导致IO很忙,而cpu却很闲)。如果有指令重排序的机制,该机制会判断这两个操作是否是相互依赖的,如果不是那就可以让(1)和(2)操作同时执行。

其中重排序可能发生在:

1)编译器优化的重排序(编译级别的重排序 编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序)

2)指令级并行的重排序(机器指令级重排序 现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序)

3)内存系统的重排序 (处理器缓存和读/写缓冲区读导致的重排序)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
volatile关键字synchronized关键字有以下几个区别: 1. 作用范围:volatile关键字只能用于变量级别,而synchronized关键字可以用于变量、方法和类级别。 2. 可见性和原子性:volatile关键字可以保证变量的可见性,即当一个线程修改了volatile变量的值,其他线程能够立即看到最新的值。但是volatile不能保证复合操作的原子性,即使是简单的i++操作也不是原子操作。而synchronized关键字既可以保证变量的可见性,也可以保证变量的原子性。 3. 阻塞:volatile关键字不会造成线程的阻塞,而synchronized关键字可能会造成线程的阻塞。 4. 编译器优化:volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化。 综上所述,volatile关键字适用于需要保证变量可见性但不需要保证原子性的场景,而synchronized关键字适用于需要保证变量可见性和原子性的场景。在需要同步的时候,首选应该是synchronized关键字,因为它是最安全的方式,并且在JDK1.5之后对synchronized同步机制进行了优化,性能也有了很大的提升。 #### 引用[.reference_title] - *1* [字节一面:synchronized和volatile关键字的区别](https://blog.csdn.net/DevolperFront/article/details/120030016)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [volatilesynchronized的区别](https://blog.csdn.net/weixin_34112208/article/details/90590873)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值