JAVA 原子性和波动性总结 Atomicity and Volality

原子性Atomicity

简单来说就是指不能被中断的一次性操作。

在JAVA中,除了long 和double的基本类型的读和写都是原子操作。这里要注意,long 和double是64位的,他们的操作被分割为两个32位操作,因此对long 和double的读和写不是原子操作。

非原子操作在多线程环境中是会出问题的,不能达到预期。

例如写一个函数,每次都返回某个变量+1,想要实现不同的线程调用它的时候都能得到不同的值,这个是做不到的。

因此在多线程中,要使用同步机制,来确保执行某个非原子操作时候对资源进行锁定,从而实现预期的效果。

Volality

原子操作在多线程中是否能达到预期?

答案是否定的,因为现在的CPU都是多核的,每个核心都会有寄存器或者缓存,某个task对某个值进行原子性操作,但此时可能另一个task运行在另一个核中,并不能识别到前面task的操作,因此尽管操作是原子性的,但不同task仍可能视角不一致。这就是Volality。翻译成 挥发性 或者 波动性

如果使用同步机制,是可以确保不发生这种情况的。

如果不用同步机制,JAVA提供了volatile修饰符,它可以保证某个field写入时候,所有的读操作都能识别到。也就是说写入时候会强制写入主内存,并迫使所有的读都从主内存中读取。

因此这里可以看出 原子性和波动性是两个不同的概念。在单线程中是不需要用volatile的。

如果不用同步机制,那么当某field依赖它之前的值时候,volatile是不生效的。(因为这个操作是非原子性操作,不能达到预期)

volatile使用的场景通常是某个类只有一个可变的属性。

看以下例子:

public class AtomicityTest implements Runnable{private int i = 0;//加 volatile 后程序无影响public int getValue(){return i;}private synchronized void evenIncrement(){i++;i++;}@Overridepublic void run() {while(true){evenIncrement();}}public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();AtomicityTest at = new AtomicityTest();exec.execute(at);while(true){int val = at.getValue();if(val % 2 !=0){System.out.print(val);System.exit(0);}}}}

i 每次都加2,希望实现i都是偶数,运行后会发现可以读到i是奇数的情况。这里即便用了volatile来修饰,而且对写的方法也加了同步机制,但仍不能达到预期。

解决办法是,对get 读的方法也使用同步机制。

原子类

JAVA SE5 提供了原子类,用于提供原子操作,有AtomicIntegerAtomicLongAtomicReference等

提供一些原子方法,我们用AtomicInteger 改造上面代码

public class AtomicIntTest implements Runnable{private volatile AtomicInteger i = new AtomicInteger(0);public int getValue(){return i.get();}private void evenIncrement(){i.addAndGet(2);}@Overridepublic void run() {while(true){evenIncrement();}}public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();AtomicIntTest at = new AtomicIntTest();exec.execute(at);while(true){int val = at.getValue();if(val % 2 !=0){System.out.print(val);System.exit(0);}}}}

可见,通过使用原子类,不使用同步机制也可以实现预期功能。

总之,可以尽量使用原子类,在不能用原子类的时候使用同步机制是可以实现预期功能的,如果你的知识足够丰富,可以使用volatile尝试去进行优化,但它只适用于少量特殊场景。

所有欺骗中,自欺是最为严重的

JAVA 原子性和波动性总结 Atomicity and Volality

相关文章:

你感兴趣的文章:

标签云: