前言 |
内容 |
什么是Volatile
可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。
在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。
三大特性
什么是原子性
即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子性其实就是保证数据一致、线程安全一部分,
什么是可见性
当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
若两个线程在不同的cpu,那么线程1改变了i的值还没刷新到主存,线程2又使用了i,那么这个i值肯定还是之前的,线程1对变量的修改线程没看到这就是可见性问题。
什么是有序性
程序执行的顺序按照代码的先后顺序执行。
一般来说处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。如下:
int a = 10; //语句1
int r = 2; //语句2
a = a + 3; //语句3
r = a*a; //语句4
则因为重排序,他还可能执行顺序为 2-1-3-4,1-3-2-4
但绝不可能 2-1-4-3,因为这打破了依赖关系。
synchronized与volatile区别
volatile
1.可以保证可见性,保证的是内存可见性
2. 但是不能保证原子性,也就是可能会存在安全性问题,禁止重排序
3. 不需要加锁比synchronized更加轻量级不会造成线程阻塞
4. volatile标记的便令不会被编译器进行优化,
5. volatile是一种变量修饰符,仅能用于变量,也就是说只能作为关键字来使用.
6. volatile是从主存中获取数据的所以在一定时候会存在问题,比如说主存中存储的数据被修改,会导致其失效.
synchronized
1.既可以保证原子性也可以保证可见性,也就是内存的可见性和操作的原子性.
2.synchronized 标记的变量会被编译器优化
3.可以作用于方法或代码块中
重排序
概念
cpu会对执行的代码进行顺序优化,但是不会对有依赖关系性的代码进行顺序调整优化,此未重排序
代码的执行顺序可能会发生变化但是执行的结果不会发生任何改变.
对于依赖关系进行解释: 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。
写后读 a = 1;b = a; 写一个变量之后,再读这个位置。
写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。
读后写 a = b;b = 1; 读一个变量之后,再写这个变量。
小结 |