-
加不加Volatile看不出有什么效果啊5
import java.util.concurrent.atomic.AtomicInteger; public class VolatilePattern1 extends Thread{ volatile boolean shutdownRequested; private AtomicInteger count = new AtomicInteger(); public void shutdown() { shutdownRequested = true; } public void run() { System.out.println("Thread:" + Thread.currentThread().getName()+" started."); while (!shutdownRequested) { System.out.println("working ..."+count); count.getAndIncrement(); try { Thread.sleep(50); } catch(InterruptedException ie) { ie.printStackTrace(); } } } public static void main(String[] args) { System.out.println("Thread:" + Thread.currentThread().getName()+" started."); VolatilePattern1 vp = new VolatilePattern1(); vp.start(); try { Thread.sleep(2000); } catch(InterruptedException ie) { ie.printStackTrace(); } finally { vp.shutdown(); } } }
2008年7月21日 11:36
2个答案 按时间排序 按投票排序
-
采纳的答案
区别在于JVM内存主存和线程工作内存的同步之上。volatile保证变量在线程工作内存和主存之间一致。以下是示例程序:
package linyumin.test.thread; /** * * @author llade * */ public class VolatileObjectTest { /** * 相信绝大多数使用JAVA的人都没试出volatile变量的区别。献给那些一直想知道volatile是如何工作的而又试验不出区别的人。 * 成员变量boolValue使用volatile和不使用volatile会有明显区别的。 * 本程序需要多试几次,就能知道两者之间的区别的。 * @param args */ public static void main(String[] args) { final VolatileObjectTest volObj=new VolatileObjectTest(); Thread t2=new Thread(){ public void run(){ System.out.println("t1 start"); for(;;){ volObj.waitToExit(); } } }; t2.start(); Thread t1=new Thread(){ public void run(){ System.out.println("t2 start"); for(;;){ volObj.swap(); } } }; t1.start(); } boolean boolValue;//加上volatile 修饰的是时候,程序会很快退出,因为volatile 保证各个线程工作内存的变量值和主存一致。所以boolValue == !boolValue就成为了可能。 public void waitToExit() { if(boolValue == !boolValue)System.exit(0);//非原子操作,理论上应该很快会被打断。实际不是,因为此时的boolValue在线程自己内部的工作内存的拷贝,因为它不会强制和主存区域同步,线程2修改了boolValue很少有机会传递到线程一的工作内存中。所以照成了假的“原子现象”。 } public void swap() {//不断反复修改boolValue,以期打断线程1. boolValue = !boolValue; } }
2008年7月21日 22:44
-
想看出效果来比较困难!
一个boolean 本省就是原子操作。
如果你换一个真正的Object,n个线程操作,你就会发现有效果了。
参见:以下为引用IBM网站上
Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。在这期的 Java 理论与实践 中,Brian Goetz 将介绍几种正确使用 volatile 变量的模式,并针对其适用性限制提出一些建议。
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。
锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。
Volatile 变量
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如 “start <=end”)。
出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时,某些习惯用法(idiom)更加易于编码和阅读。此外,volatile 变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题。在某些情况下,如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势。
正确使用 volatile 变量的条件
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值。
该变量没有包含在具有其他变量的不变式中。
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)
大多数编程情形都会与这两个条件的其中之一冲突,使得 volatile 变量不能像 synchronized 那样普遍适用于实现线程安全。清单 1 显示了一个非线程安全的数值范围类。它包含了一个不变式 —— 下界总是小于或等于上界。2008年7月21日 16:58
相关推荐
比如,在上面的示例程序中,如果不使用 volatile,编译器可能会将四条语句优化成一条,忽略前三条语句。但是,如果使用 volatile,编译器将逐一编译每条语句,产生四条机器代码。 volatile 变量的应用场景包括: 1...
- volatile不能替代锁:尽管volatile可以保证可见性,但无法保证原子性。例如,两个线程同时读写一个volatile变量,可能导致数据不一致。 - volatile与指针:如果指针本身是volatile,意味着指针的值(地址)可能...
* 下面的函数有什么错误:intsquare(volatile int*ptr){return *ptrptr;}答案是这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:intsquare...
2. volatile修饰符不能与const修饰符同时使用,因为volatile修饰符意味着变量的值可能会改变,而const修饰符意味着变量的值不能改变。 3. 使用volatile修饰符可能会影响编译器的优化,因此需要根据实际情况进行选择...
在多线程共享变量并使用互斥锁保护时,加不加volatile可能不会有实质区别,因为互斥锁已经保证了对内存的访问顺序。但在没有同步机制的多线程环境中,或者涉及到硬件设备、非线性控制流时,volatile是不可或缺的,以...
3. **下面的函数有什么错误:** ```c int square(volatile int *ptr) { return *ptr * *ptr; } ``` - 这段代码存在问题。它的目的是返回指针`ptr`指向值的平方,但由于`ptr`指向的是一个`volatile`型参数,...
5. `volatile`与`const`结合:`volatile const`变量表示其值可以被外部因素改变,但程序内部不应尝试修改。 在面试和找工作中,理解和掌握`const`和`volatile`的使用是评估程序员基础功底的重要标准。熟悉它们可以...
* volatile 变量不能提供原子特性,因此不能用于实现计数器、互斥锁或任何具有与多个变量相关的不变式。 * volatile 变量的使用需要满足两个条件:对变量的写操作不依赖于当前值,以及该变量没有包含在具有其他变量...
一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,...
当一个变量被声明为`volatile`时,编译器会知道这个变量的值可能在运行时被外部不可预见的因素(比如硬件中断、多线程等)修改。因此,每次访问`volatile`变量时,都会从内存中读取最新的值,而不是依赖于寄存器中...
如果不使用`volatile`,编译器可能会优化代码,只读取一次值并将其存放在寄存器中,从而导致错误的结果。 #### 正确示例 ```c uint32_t square(uint32_t *ptr) { return *ptr * *ptr; } ``` 在这个例子中,由于`*...
在 C 语言中,volatile 关键字是用来指定变量的存储类别的,它告诉编译器这个变量的值可能会在编译器不知道的情况下被修改,因此需要重新加载这个变量的值。volatile 关键字的使用方法可以分为两种情况:一是用来...
在深入理解volatile时,我们需要考虑JVM内存模型、处理器缓存以及底层的汇编指令,这有助于我们更好地理解和使用volatile,解决并发编程中的问题。在实际开发中,合理利用volatile可以避免不必要的锁同步,提升程序...
例如,如果你有一个计数器并尝试通过多个线程同时递增,volatile并不能保证递增操作的原子性,因此仍然需要使用synchronized或者其他并发控制机制来保证。 下面是一些关于volatile的常见问题及其解答: 1. **参数...
这里的`const`表明程序不应尝试修改这个寄存器的值,而`volatile`则表示该寄存器的值可能被外部因素改变。 2. **volatile指针**:指针也可以被声明为`volatile`,这在中断服务子程序中修改指向缓冲区的指针时非常...
volatile关键字用于告诉编译器不要对变量进行优化,而原子操作则是指不可中断的操作。在本文中,我们将探究volatile和原子操作的关系,并通过实验代码和结果来加以验证。 首先,让我们看一下volatile的定义。...
2. 多任务环境下的用法:在多任务系统中,如果有多个任务共享同一个变量,为了保证变量值的实时性和准确性,应当将共享变量声明为volatile。这样,无论何时读取该变量,都将直接从内存中获取最新值,而不是使用可能...
如果这些变量不声明为volatile,编译器可能会优化掉对它们的读取和写入,导致程序行为不符合预期。 例如,在GD32F303的中断服务程序中,可能需要更新一个标志位来指示中断已处理。如果不声明这个标志位为volatile,...
- 当一个变量被声明为`volatile`时,意味着编译器在使用这个变量时不能假设它的值是不变的。 - 每次访问`volatile`变量时,编译器都会确保从内存中重新加载该变量的值,而不是使用寄存器中的备份。 - 这有助于防止...