1.Volatile是否保证原子性
package charter2;
/**
* @Auther: 洺润Star
* @Date: 2020/4/11 11:30
* @Description:测试Volatile是否能保证原子性
*/
public class TesetVolatileAtomicity {
public static volatile int cnt =0;
public static void add(){
//延迟1毫秒,增加多线程并发抢占的概率。
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
cnt++;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(new Runnable() {
@Override
public void run() {
TesetVolatileAtomicity.add();
}
}).start();
}
//每次运行结果都有可能不同
System.out.println(TesetVolatileAtomicity.cnt);//267
}
}
通过代码创建1000个线程进行++操作,可以看到结果是一定是小于1000的,毫无疑问Volatile不能保证原子性。
2. Volatile特性一:禁止重排序
多线程环境下重排序会造成意想不到的结果,而如果对变量添加Volatile进行修饰则可禁止重排序优化,从而防止重排序对多线程的影响。
在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果(这也是as-if-serial语义允许对存在控制依赖的操作做重排序的原因);但在多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。
3. Volatile特性二:保证线程间可见
• 对线程内存变量的写操作,能立即写回主内存
• 能实现并发的HashMap也就是ConcurrentHashMap,其中定义了map的长度
private transient volatile long baseCount;
存储该对象长度的变量是volatile
多个线程同时读写该ConcurrentHashMap对象,对长度的修改能立即让其它线程感知
线程可见性举例:
package charter2;
/**
* @Auther: 洺润Star
* @Date: 2020/4/11 11:16
* @Description:测试VolatileForVisible 主线程变量的修改不能影响线程变量
*/
public class TestVolatileForVisible extends Thread{
boolean stopFlag = false;
public int cnt = 0;
@Override
public void run() {
while (!stopFlag){
cnt++;
}
System.out.println("我终止了");
}
public static void main(String[] args) throws InterruptedException {
TestVolatileForVisible testVolatileForVisible = new TestVolatileForVisible();
testVolatileForVisible.start();
Thread.sleep(5000);
testVolatileForVisible.stopFlag = true;
System.out.println(testVolatileForVisible.cnt);
}
}
代码中在不添加volatile的情况下虽然说也会输出cnt值的大小,但是程序不会停止。
因为虽然将stopFlag设为了true但由于线程不可见性run方法所在的线程stopFlag值仍未false并没有及时更新 所以线程不会停止
volatile boolean stopFlag = false;
添加volatile后,stopFlag 会及时加载到主内存中,所有线程内存中stopFlag值 将会一致,所以线程将会被停止掉。