java中非volatile变量读取是从工作内存中读取,不一定可以读到主内存的最新数据。volatile变量保证每次读取都要从主内存中拿。
写了一段代码来验证这一点
public class MemoryMode { private volatile boolean flag = false;//这个类型是volatile的时候,结果是conditionChanged:true public void setFlag(){ flag = true; } private boolean conditionChanged = false; public static class LoopRunnable implements Runnable{ private MemoryMode memoryMode; public LoopRunnable(MemoryMode memoryMode){ this.memoryMode = memoryMode; } public void run() { while (true){//标记未改变,一直循环 if(memoryMode.flag){ memoryMode.conditionChanged = true; break; } } } } public static class SetFlagRunnable implements Runnable{ private MemoryMode memoryMode; public SetFlagRunnable(MemoryMode memoryMode){ this.memoryMode = memoryMode; } public void run() { memoryMode.setFlag();//改变标记值 } } public static void main(String[] args) throws InterruptedException { MemoryMode memoryMode = new MemoryMode(); LoopRunnable loopRunnable = new LoopRunnable(memoryMode); Thread a = new Thread(loopRunnable); Thread b = new Thread(new SetFlagRunnable(memoryMode)); a.start(); Thread.sleep(10000); b.start(); a.join(); b.join(); System.out.print("conditionChanged:"+memoryMode.conditionChanged); } }
上面这段代码申明了一个volatile修饰的名称为flag的变量,初始值为false。启动一个线程a,run方法是一个死循环,flag为true时才退出循环。然后启动另外一个线程b,改变flag的值到true。因为flag一个volatile变量,值被线程b改变后,对线程a是立即可见的,所以可以代码可以正常退出。
把上面的代码修改一下,去掉flag对象的volatile修饰。期待a线程一直读不到flag的值变为true,代码一直循环,不能正常退出。
在Intellij里,选择run as application,和期望的一样,代码确实不能正常退出。但是,如果选择的是debug as application的话,代码可以正常退出的,和标记为volatile的效果一样。
可以猜想,debug模式下,所有变量都是从主内存中读取的。
相关推荐
在Debug版本中,为了提高调试的便利性,编译器可能会保留所有标记为`volatile`的变量,即使这些变量在实际运行中并没有发生变化。这样做有助于确保程序状态的一致性和可预测性,尤其是在多线程环境中。 而在Release...
volatile关键字的作用是提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,...
然而,在debug模式下执行时,由于编译器进行了优化,导致`b`的值仍然为10,而不是更新后的32。这说明了如果没有使用`volatile`关键字,编译器可能会缓存`i`的值,即使其实际值已经发生了变化。 #### (2) 使用`...
* volatile 型变量:volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统、其他进程和线程)。优化程序为了使程序性能提高,常把一些变量放在寄存器中(类似于 register 关键字),而其他进程只能对该...
在“Debug”目录下,可能包含编译和调试这些代码时生成的中间文件和输出,这对于调试和理解程序的运行情况非常有用。 总之,变量的存储类型是编程中的核心概念,理解和熟练运用这些类型能帮助开发者编写出更加健壮...
2. **volatile关键字**:在Java和C++中,volatile关键字用于确保多线程环境下的可见性和有序性,但不能保证原子性。 3. **原子操作**:不可分割的操作,例如 increment 操作,需要通过原子操作保证在多线程环境中的...
在多线程环境下,如果一个变量可能被其他线程修改,将其声明为`volatile` 可以保证其可见性,但不保证原子性。 2. **Interlocked函数系列**: Windows API 提供了一系列的`Interlocked`函数(如`...
在开发过程中,`volatile`的使用有助于保证程序在不同编译器和优化级别下的正确性。在Debug版本中,编译器的优化程度较低,程序可能运行正常,但在Release版本中,由于编译器的更激进优化,未声明为`volatile`的变量...
需要注意的是,volatile 关键字并不能解决所有线程安全问题,它仅仅保证了变量的可见性,而不能保证操作的原子性。例如,如果你有一个计数器需要在多线程中递增,volatile 无法防止竞态条件,你需要使用锁或其他并发...
- **输出**:格式为 `"=c"(变量名)"..."`,其中 `"=c"` 表示输出约束,用于告诉编译器输出变量的值可能会被修改。 - **输入**:格式为 `"c"(变量名)"..."`,其中 `"c"` 表示输入约束,用于告诉编译器输入变量的值...
但synchronized可以确保在释放锁之前,所有修改过的变量都可见,而volatile则没有这个保证。 Java 1.5引入的Lock接口扩展了同步机制,提供了更灵活的控制。ReentrantLock是Lock的一个实现,它也是可重入的,意味着...
例如,auto 声明自动变量,break 跳出当前循环,case 开关语句分支,char 声明字符型变量或函数返回值类型,const 声明只读变量,continue 结束当前循环,开始下一轮循环,default 开关语句中的“默认”分支,do ...
- **volatile**: 表明变量可能在没有明确程序控制的情况下发生变化,通常用于硬件接口编程中。 ### LED闪烁示例 最后,文件中还包含了一个简单的LED闪烁程序示例,展示了如何使用ARM汇编和C语言混合编程来控制LED...
- 文件中提到了ARM7的不同工作模式,包括用户模式、快速中断模式(FIQ)、普通中断模式(IQR)、系统调用模式(SVC)、中止模式(Abort)、未定义模式(Undefined)和系统模式(System),每种模式对应不同的特权级别。...
`volatile`关键字用于指示编译器不要优化对某个变量的访问。 **示例**: ```c volatile int i = 0; // 定义了一个易变的整型变量 ``` **解析**: - 对于硬件接口或外部设备的状态等,使用`volatile`可以确保程序...
volatile 关键字是指在多线程环境下,如何保证变量的可见性和原子性。 volatile 关键字的作用:保证变量的可见性、保证变量的原子性。 九、Lock 机制 Lock 机制是指在多线程环境下,如何保护共享资源不被多个线程...
为了解决这个问题,通常需要在全局变量前使用关键字volatile进行修饰,这可以告诉编译器该变量可能会被硬件或中断服务程序改变,避免编译器对这些变量进行优化处理。此外,在读取这些变量之前,应当暂时关闭全局中断...
- 日志级别分为DEBUG、INFO、WARN、ERROR,根据需要选择合适的级别。 10. **测试**: - 编写单元测试用例,确保代码功能的正确性。 - 使用JUnit、Mockito等工具进行测试驱动开发。 以上仅为部分Java开发规范,...
一个变量可以多次声明,但只能有一次定义。例如: ```cpp extern int A; // 声明A为已定义的外部变量 int main() { extern int A; // 声明 dosth(); // 使用 } int A; // 定义 ``` 使用`extern`关键字声明...