java中volatile和synchronized的区别

voalite

volatile修饰的变量具有可见性,对变量的操作在内存中进行,对所有线程共享变量,并且局部阻止了指令重排的发生,限制编译器对修饰变量的相关读写操作和指令重排。

volatile和synchronized的区别

  1. volatile仅能使用在变量上,synchronized可以使用在变量和方法与类级别上;
  2. volatile仅能实现变量的可见性,不能保证原子性,synchronized可以保证变量的可见性和原子性;
  3. volatile不会造成线程阻塞,synchronized可能会造成线程阻塞(因为volatile只是将当前变量的值及时告知所有线程,而synchronized是锁定当前变量不让其它线程访问);
  4. volatile标记的变量不会被编译器优化(因为不能指令重排),synchronized标记的变量可以被编译器优化;
  5. volatile修饰变量适合于一写多读的并发场景,而多写场景一定会产生线程安全问题(因此使用volatile而不是synchronized的唯一安全情况是类中只有一个可变的域)。
  6. 因为所有的操作都需要同步给内存变量,所以volatile一定会使线程的执行速度变慢。

volatile与static
volatile:保证一致性,不保证唯一性,多个实例有多个volatile变量。
static:保证唯一性,不保证一致性,多个实例共享一个静态变量。

volatile详细解释

volatile 关键字能把 Java 变量标记成"被存储到主存中"。这表示每一次读取 volatile 变量都会访问计算机主存,而不是 CPU 缓存。每一次对 volatile 变量的写操作不仅会写到 CPU 缓存,还会刷新到主存中。

举个例子,在多线程 (不使用 volatile) 环境中,每个线程会从主存中复制变量到 CPU 缓存 (以提高性能)。如果你有多个 CPU,不同线程也许会运行在不同的 CPU 上,并把主存中的变量复制到各自的 CPU 缓存中,像下图画的那样

在这里插入图片描述
若果不使用 volatile 关键字,你无法保证 JVM 什么时候从主存中读变量到 CPU cache,或把变量从 CPU cache 写回主存。这会导致很多并发问题。

想像一下这种情形,两个或多个线程同时访问一个共享对象,对象中包含一个用于计数的变量:

public class SharedObject {
public int counter = 0;

}

假设 Thread-1 会增加 counter 的值,而 Thread-1 和 Thread-2 会不时地读取 counter 变量。在这种情形中,如果变量 counter 没有被声明成 volatile,就无法保证 counter 的值何时会 (被 Thread-1) 从 CPU cache 写回到主存。结果导致 counter 在 CPU 缓存的值和主存中的不一致。

Thread-2 无法读取到变量最新的值,因为 Thread-1 没有把更新后的值写回到主存中。这被称作 “可见性” 问题,即其他线程对某线程更新操作不可见。

在这里插入图片描述

volatile 保证了变量的可见性
volatile 关键字解决了变量的可见性问题。通过把变量 counter 声明为 volatile,任何对 counter 的写操作都会立即刷新到主存。同样的,所有对 counter 的读操作都会直接从主存中读取。

public class SharedObject {
public volatile int counter = 0;

}

还是上面的情形,声明 volatile 后,若 Thread-1 修改了 counter 则会立即刷新到主存中,Thread-2 从主存读取的 counter 是 Thread-1 更新后的值,保证了 Thread-2 对变量的可见性。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Javasynchronizedvolatile是用来实现多线程同步的关键字。它们在实现多线程同步的机制上有一些不同之处。 首先,synchronized关键字提供了互斥访问的能力,即同一时刻只允许一个线程访问被synchronized修饰的代码块或方法。它可以解决并发编程的原子性、可见性和有序性问题。通过获取锁来实现同步,保证了代码的原子性和有序性。同时,synchronized也保证了共享变量在不同线程之间的可见性。 而volatile关键字主要用来解决共享变量的可见性和有序性问题。使用volatile修饰的变量会强制线程从主内存读取变量的最新值,而不是使用缓存的旧值。这样可以确保一个线程对volatile变量的修改对其他线程是可见的。然而,volatile不能保证原子性,因此在执行复合操作时仍然需要加锁来保证原子性。 此外,synchronized关键字可以用于修饰代码块或方法,而volatile只能修饰变量。另外,synchronized是悲观锁,会导致线程阻塞等待锁的释放,而volatile是乐观锁,不会阻塞线程,而是要求线程自己通过CAS操作来保证数据一致性。 综上所述,synchronizedvolatile关键字在实现多线程同步的机制上有一些不同。synchronized提供了更全面的多线程同步能力,可以解决原子性、可见性和有序性问题,但会引入线程阻塞。而volatile关键字主要解决共享变量的可见性和有序性问题,但无法保证原子性。因此,在选择使用synchronized还是volatile时,需要根据具体的应用场景和需求进行权衡。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [synchronizedvolatile区别是什么?](https://blog.csdn.net/m0_68464502/article/details/131107637)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [4个点说清楚Javasynchronizedvolatile区别](https://blog.csdn.net/wanghao112956/article/details/100133457)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java关键字volatilesynchronized作用和区别](https://download.csdn.net/download/weixin_38557838/12778536)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值