package net.concurrent;
public class MutableInteger {
private int value;
public int get() {
return this.value;
}
public void set(int value) {
this.value = value;
}
}
在多线程环境下,MutableInteger 不是线程安全的,set/get 在没有同步的情况下访问value,数据失效的问题可能会出现。有的线程能够看到最新的数据,有些则看不到
package net.concurrent;
public class MutableInteger {
private int value;
public synchronized int get() {
return this.value;
}
public synchronized void set(int value) {
this.value = value;
}
}
通过synchronized 使MutableInteger 成为线程安全的类,紧紧对set同步是不够的,因为get 仍然是会读到失效的数据,通过上一章我们清楚synchronized 是可以保证内存的可见性的,当然我们还可以使用其他的方式如下:
Volatile变量
volatile 提供了稍微弱一点的锁机制,用来确保将变量的更新操作通知到其他的线程当中,如果变量声明成volatile,表明这个变量是共享的,仅此不会出现与其他内存操作重排序操作,volatile变量不会缓存到寄存器中。因此读到volatile 操作总是最新的值。
package net.concurrent;
public class MutableInteger {
private volatile int value;
public int get() {
return this.value;
}
public void set(int value) {
this.value = value;
}
}
在访问value值不会执行加锁操作,就不会出现线程堵塞状态,同时又能保证内存可见性,因此Volatile是一种比Synchronized 关键字更轻量级的同步机制.
从内存可见性的角度来分析,写入volatile变量相当于退出了同步代码块,而读取volatile变量相当于进入了同步代码块,然而我们并不建议过度的依赖volatile内存可见性。过度的应用会比synchronized的代码更脆弱也更难以理解.
虽然volatile变量很方便,但也存在一切局限性。volatile关键字通常用作于:某个操作完成、发生中断、或者状态标示.volatile不足以确保原子操作。只能保证可见性