volatile的特性:
对单个变量的读/写可以看成锁对单个变量所做的同步。
class VolatileFeaturesExample {
volatile long vl = 0L; // 使用volatile声明64位的long型变量
public void set(long l) {
vl = l; // 单个volatile变量的写
}
public void getAndIncrement () {
vl++; // 复合(多个)volatile变量的读/写
}
public long get() {
return vl; // 单个volatile变量的读
}
}
class VolatileFeaturesExample {
long vl = 0L; // 64位的long型普通变量
public synchronized void set(long l) { // 对单个的普通变量的写用同一个锁同步
vl = l;
}
public void getAndIncrement () { // 普通方法调用
long temp = get(); // 调用已同步的读方法
temp += 1L; // 普通写操作
set(temp); // 调用已同步的写方法
}
public synchronized long get() { // 对单个的普通变量的读用同一个锁同步
return vl;
}
}
可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。
volatile写/读的内存语义:
当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
通过把写线程修改的结果写入主存中,设置其他线程本地内存包含的值设置为无效,因此其他线程需要重新从主存读取来保证数据的一致性。
对volatile变量写入与读取的过程,形式上类似线程间的通信。
sychronized:
锁释放与volatile写有相同的内存语义,锁获取与volatile读有相同的内存语义。
sychronized与volatile区别:
- 都具有可见性
- 使用方面上,volatile:变量,synhronized:方法,变量
- volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile不会阻塞线程,synchronized会组赛线程
- volatile标记的变量不会被编译器优化,synchronized的会被优化
- 单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。synchronized具有原子性