volatile和synchronized区别

volatile:

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

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

volatile修饰的变量进行写操作时,转成汇编码时多出Lock 指令。Lock指令的作用:将缓存数据写到住内存,使其他CPU里的缓存数据失效。

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对象所有同步代码部分的访问都被暂时阻塞。

synchronized  同步代码块时,汇编码代码部分的前后会多出 monitorenter  和
monitorexit 指令。每个对象( synchronized的参数)都有一个monitor(监视器锁)每个 monitor 都有一个进入数(我叫他enternum,为1时标识已占有,为0时表示退出)。 monitorenter 表示线程进入monitor, enternum加1,已占有的线程重入时 enternum 加1; monitorexit表示 enternum 减1。

区别:

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注