volatile修饰全局变量,可以保证线程并发安全吗?
今天被人问到volatile能不能保证并发安全?
呵,这能难倒我?
直接上代码:
public class ThreadTest { // 使用volatile修饰变量 private static volatile int num = 0; public static void main(String[] args) throws InterruptedException { // 循环创建10个线程并执行,每个线程内对volatile修饰的num进行递增 for (int i = 0; i < 10; i++) { new Thread(() -> { for (int ii = 0; ii < 1000; ii++) { autoIncrement(); // autoIncrementLock(); // System.out.println(num); 这是一个彩蛋,猜猜看sout打印会不会影响结果? } }).start(); } // 睡眠3秒以等待每个线程内递增结束 Thread.sleep(3000); System.out.println("最终结果为:"+num); } // 无锁递增 private static void autoIncrement() { num++; } // 使用synchronized修饰递增方法,给其上锁 private static synchronized void autoIncrementLock() { num++; } }
期望最终值:
10 * 1000 = 10000
运行无锁autoIncrement()三次,结果分别为:
第一次:8666
第二次:7767
第三次:9084
运行被synchronized修饰的方法三次,结果分别为:
第一次:10000
第二次:10000
第三次:10000
分析:
10个线程对volatilei修饰的num++,会被编译成以下三步:
- 获取num的值;
- 执行num+1;
- 将结果赋值给num。
volatile关键字只能保证可见性,并不能保证原子性。
结论:
volatile关键字只能保证这3步在编译后指令不会被重新排序,并不能保证多个线程并发的数据安全。建议在方法上加上synchronized修饰或配合其他Lock锁使用。
本文来自博客园,作者:杨飞只是太过正经,转载请注明原文链接:https://www.cnblogs.com/yangfei666/p/14686844.html

浙公网安备 33010602011771号