Java Web房屋租赁系统源码部署与二次开发实战指南
2026/9/28 17:06:39
使用volatile修饰基本数据类型和引用数据类型的主要区别在于作用范围不同:
privatevolatileintcount=0;count的修改对其他线程立即可见count++)的原子性privatevolatileMyObjectobj=newMyObject();obj引用的修改(指向新对象)对其他线程立即可见obj = new MyObject()不会被重排序到初始化之前classSharedData{privatevolatileintvalue=0;// 线程Apublicvoidwriter(){value=42;// 修改立即对其他线程可见}// 线程Bpublicvoidreader(){System.out.println(value);// 一定能看到最新的值}}classMyObject{intx=0;inty=0;}classSharedData{privatevolatileMyObjectobj=newMyObject();// 线程Apublicvoidwriter(){// 保证新对象引用对其他线程可见obj=newMyObject();obj.x=1;// ⚠️ 这些修改对其他线程不一定可见!obj.y=2;}// 线程Bpublicvoidreader(){MyObjectlocal=obj;// 能获取到最新的引用// 但可能看不到 obj.x 和 obj.y 的最新值System.out.println(local.x+", "+local.y);}}// ❌ 错误:认为volatile能保证对象内部状态的可见性privatevolatileUseruser=newUser("Alice",25);// 只能保证user引用变更的可见性,不能保证user.name和user.age的修改可见// ✅ 正确做法:如果对象内部状态也需要可见性classUser{privatevolatileStringname;privatevolatileintage;// 或者使用其他同步机制}classSingleton{privatestaticvolatileSingletoninstance;publicstaticSingletongetInstance(){if(instance==null){// 第一次检查synchronized(Singleton.class){if(instance==null){// 第二次检查instance=newSingleton();}}}returninstance;}}这里volatile确保instance引用的初始化对其他线程立即可见,防止指令重排序导致返回部分初始化的对象。
| 特性 | 基本数据类型 | 引用数据类型 |
|---|---|---|
| 可见性保证 | 变量值修改可见 | 引用变更可见 |
| 有序性保证 | 变量操作不重排 | 引用赋值不重排 |
| 原子性 | 单次读写原子 | 引用赋值原子 |
| 作用范围 | 变量本身 | 引用本身,不包含对象内部 |
| 线程安全 | 需要额外同步 | 需要额外同步(对象内部) |
对于基本数据类型:使用volatile当需要保证可见性且操作是原子性的(如赋值、读取)
对于引用数据类型:
volatilesynchronized、AtomicReference等)替代方案:考虑使用java.util.concurrent.atomic包中的原子类,它们提供了更丰富的原子操作。