原子操作要么不发生,要么全部发生。
下面是原子的:
(1)读写基本类型数据(long和double除外)
(2)volatile修饰的变量(包含long和double)读写原子
原子动作不能重叠,不用担心线程干扰了,但是这不意味着就不用同步了,因为内存一致性的错误还是可能的。
使用volatile变量减少了内存一致性错误的风险,因为任何写volatile变量建立一个happen-before原则给 后面读同一个变量的操作。这就意味着,改变一个volatile变量对其他
线程总是可见的。更多的,当一个线程读一个volatile变量,他看到的不仅仅是volatile最新的改变,还包含导致这个变化的代码的副作用(??)
使用原子变量访问比synchronized代码更高效,但是要求程序员更加关心内存一致性问题。是否值得额外的努力取决于程序的大小和复杂程度。
下面这个应该是没有处理内存一致性,所以结果不会是100*10000,加上volatile反而不如不加得到的结果大。
public class VolatileTest {
public static volatile int count=0;
public static void increase(){
count++;
}
private static final int THREADS_COUNT = 100;
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_COUNT];
for(int i =0; i< THREADS_COUNT; i++){
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0; i < 10000; i++){
increase();
}
}
});
threads[i].start();
}
while(Thread.activeCount() > 1){
Thread.yield();
}
System.out.println(count);
}
}
使用volatile虽然保证了可见性,但是内存一致性还是要解决。
不符合下面的规则也是要同步保证原子性:
(1)运算结果不依赖变量当前值(++操作显然不符合),或者能够确保只有一个线程修改变量的值
(2)变量不需要与其他状态变量共同参与不变约束(这个不太理解啊?)
根据第一天,volatile变量作为线程之间公共属性貌似可以,不过要谨慎处理。