java中volatile关键字一文中,提到了volatile不具备"互斥性"、不能保证变量的"原子性"。
原子性即不可分割性,在程序中指的是一个操作,要么全部执行成功,要么全部执行失败,不可能执行被打断。
例如:i++操作 实际上是三步操作 这三步操作分别是
- 读 int temp = i;
- 改 i = i + 1;
- 写 i = temp;
可见i++并不具备原子性。如下代码也可说明其不具备原子性
public class TestAtomicDemo
{
public static void main(String[] args)
{
AtomicDemo atomicDemo = new AtomicDemo();
//开启十个线程
for (int i = 0; i < 5; i++)
{
new Thread(atomicDemo).start();
}
}
}
class AtomicDemo implements Runnable
{
private int serialNumber = 0;
@Override
public void run()
{
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(getSerialNumber());
}
public int getSerialNumber()
{
return serialNumber++;
}
}
运行结果如下:
0
0
1
2
3
通过volatile关键字也是不能解决这个问题的,可以通过用volatile关键字修饰serialNumber变量尝试。这种情况可以通过同步代码块或者同步函数解决,也可以通过原子变量解决, 在JAVA API java.util.concurrent.atomic 包中可以看到原子变量类。
修改代码如下:
public class TestAtomicDemo
{
public static void main(String[] args)
{
AtomicDemo atomicDemo = new AtomicDemo();
//开启十个线程
for (int i = 0; i < 5; i++)
{
new Thread(atomicDemo).start();
}
}
}
class AtomicDemo implements Runnable
{
//private int serialNumber = 0;
//创建原子整型变量
AtomicInteger serialNumber = new AtomicInteger(0);
@Override
public void run()
{
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(getSerialNumber());
}
public int getSerialNumber()
{
return serialNumber.getAndIncrement();
}
}
原子变量通过volatile修饰保证变量内存可见性。通过CAS(Compare-And-Swap)算法保证数据的原子性。