volatile和synchronize的区别

原子性(atomicity)和可见性(visibility)

原子性意味着一个时刻,只有一个线程能够执行一段代码,这段代码通过一个monitor object保护。从而防止多个线程在更新共享状态时相互冲突。
可见性则更为微妙,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的。如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。

volatile

它所修饰的变量不保留拷贝,直接访问主内存中的。

在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。 一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。

使用场景

您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
1)对变量的写操作不依赖于当前值。
2)该变量没有包含在具有其他变量的不变式中。

volatile最适用一个线程写,多个线程读的场合。
如果有多个线程并发写操作,仍然需要使用锁或者线程安全的容器或者原子变量来代替。

synchronized

当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码

  1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
  2. 然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
  3. 尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
  4. 当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞

区别

  1. volatile是变量修饰符,而synchronized则作用于一段代码或方法
  2. volatile只是在线程内存和“主”内存间同步某个变量的值;而synchronized通过锁定和解锁某个监视器同步所有变量的值, 显然synchronized要比volatile消耗更多资源。
  3. volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  4. volatile保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存中和公共内存中的数据做同步。
  5. volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

线程安全包含原子性和可见性两个方面,Java的同步机制都是围绕这两个方面来确保线程安全的。
关键字volatile主要使用的场合是在多个线程中可以感知实例变量被修改,并且可以获得最新的值使用,也就是多线程读取共享变量时可以获得最新值使用。

关键字volatile提示线程每次从共享内存中读取变量,而不是私有内存中读取,这样就保证了同步数据的可见性。但是要注意的是:如果修改实例变量中的数据

例如:i++,也就是i=i+1,则这样的操作其实并不是一个原子操作,也就是非线程安全的。表达式i++操作步骤分解如下:
1)从内存中取出i的值。
2)计算i的值;
3)将i的值写到内存中。
假如在第2步计算值得时候,另外一个线程也修改i的值,name这个时候就会出现脏读数据。解决的办法就是使用synchronized关键字。 所以说volatile本身并不处理数据的原子性,而是强制对数据的读写及时的影响到主内存中。

参考:
https://www.jianshu.com/p/0a6ca9c7695b (JAVA过关题-Volatile和Synchronize)
https://blog.csdn.net/it_manman/article/details/79497807 (volatile和synchronize的区别)
https://blog.csdn.net/mccand1234/article/details/52139319 (java 内存模型)
https://www.cnblogs.com/hrlizhi/p/9418009.html (多线程 volatile关键字)
https://blog.csdn.net/vking_wang/article/details/9982709 (volatile的适用场景)
https://www.jianshu.com/p/c6f190018db1 (指令重排序)

猜你喜欢

转载自blog.csdn.net/mccand1234/article/details/91345168
今日推荐