网站设计网站整站多关键词优化
1.volatile本质是在告诉JVM当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取。synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2.volatile仅能使用在变量级别;
synchronized则可以使用在变量、方法、和类级别。
3.volatile仅能实现变量的修改可见性,不能保证原子性;
而synchronized则可以保证变量的修改可见性和原子性
4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
JVM的原子性、可见性、有序性介绍:
(此部分参考:
https://blog.csdn.net/u012723673/article/details/80682208.)
原子性
是指一个操作或多个操作要么全部执行,且执行的过程不会被任何因素打断,要么就都不执行。
原子性是拒绝多线程操作的,不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。
简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。
例如 a=1是原子性操作,但是a++和a +=1就不是原子性操作。
Java中的原子性操作包括:
a. 基本类型的读取和赋值操作,且赋值必须是数字赋值给变量,变量之间的相互赋值不是原子性操作。
b.所有引用reference的赋值操作
c.java.concurrent.Atomic.* 包中所有类的一切操作
可见性
可见性是指:当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改。
在多线程环境下,一个线程对共享变量的操作对其他线程是不可见的。
Java提供了volatile来保证可见性,当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。
当然,synchronize和Lock都可以保证可见性。
synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
有序性
即程序执行的顺序按照代码的先后顺序执行。
Java内存模型中的有序性可以总结为:
如果在本线程内观察,所有操作都是有序的;
如果在一个线程中观察另一个线程,所有操作都是无序的。
前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工作内存和主内存同步延迟”现象。
在Java内存模型中,为了效率是允许编译器和处理器对指令进行重排序,当然重排序不会影响单线程的运行结果,但是对多线程会有影响。
Java提供volatile来保证一定的有序性。最著名的例子就是单例模式里面的DCL(双重检查锁)。
另外,可以通过synchronized和Lock来保证有序性,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。