volatile作用:是为了解决内存不可见(线程不可见问题)。什么是内存不可见。请看下面的例子
例子:
//任务类
class ThreadDemo implements Runnable{
public boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
}
}
//main方法测试
public static void main(String[] args){
ThreadDemo t1 = new ThreadDemo();
new Thread(t1).start();
while(true){
synchronized (t1){
if (t1.flag){
System.out.println("-----------");
break;
}
}
}
}
运行结果:
从上面的程可知,有两个线程分别是t1和main线程。t1用来修改flag的值,main线程用来读flag的值。但是没有读到。原因就是内存不可见。
两个线程开始时都将数据读到自己的拥有的内存当中再执行,main线程中的while循环是一个特别高效的语句,执行速度很快main执行起来没有时间区再去读主存当中的flag变量,所以造成线程不可见现象。
解决方案1:在使用volatile关键字
public volatile boolean flag = false;
执行结果:
方案2:使用synchronized关键字
while(true){
synchronized (t1){
if (t1.flag){
System.out.println("-----------");
break;
}
}
}
这样每次判断前让main线程重新读取一下t1对象。但是这样效率很差,远远不如volatile关键字。但是他们各有优势。volatile不能保证变量的原子性。那咱说一说数据的原子性。
例子:
//main
AtomicThread a = new AtomicThread();
for(int i =0 ; i < 10 ;i++){
new Thread(a).start();
}
//任务类
class AtomicThread implements Runnable{
int number = 0;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---"+number++);
}
}
```结果:

出现这种的现象的原因就是破坏了原子性。
解决方案:将变量定义为原子变量,(java1.5后)
AtomicInteger number = new AtomicInteger(0);
System.out.println(Thread.currentThread().getName()+"---"+number.getAndIncrement());
原子变量实现的原理:
<1>原子变量一定是内存可见的都是被volatile关键字修饰的
<2>CAS算法(Compare and Swap)
CAS算法:
内存值:V
预期值:A
更新值:B
当且仅当V=A的时候才更新B,不然啥操作也不做。
public class ComapreAndSwap {
public static void main(String[] args){
CAS cas = new CAS();
for (int i =0 ; i< 5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(cas.setValue(0,2));
}
}).start();
}
}
}
class CAS{
private int number;
synchronized public int getNumber(){
return number;
}
synchronized public int compare(int expectValue,int updateValue){
int oldValue = this.number;
if (oldValue == expectValue){
this.number = updateValue;
}
return oldValue;
}
synchronized boolean setValue(int expectValue,int updateValue){
return expectValue == compare(expectValue,updateValue);
}
}