本文目录
- 嵌入式c编程中的volatile关键字有何作用
- volatile关键字的作用
- Java中怎么理解volition关键字
- volatile关键字的使用场景
- java里volatile关键字有什么特性
- volatile关键字在Java中有什么作用
嵌入式c编程中的volatile关键字有何作用
为了避免编译器进行优化吧好像,比如为了实现无操作延时:
asm("mov r0, r0");
可能会被编译器优化掉,但是如果加上volatile关键字,就不会被优化,而是严格按照编写的代码放入汇编后的文件中:
asm volatile("mov r0, r0");
这样就可以实现不被优化
volatile关键字的作用
作用:1.保证变量写操作的可见性
2.保证变量前后代码的执行顺序
volatile 关键字告诉编译器该变量可能会在程序的任意时刻被改变,不应该被优化或缓存,每次访问该变量时都应该从内存中读取。在多线程程序中,如果一个变量可能被多个线程同时访问和修改,那么就应该将其声明为 volatile,以确保每个线程都能看到该变量的最新值。
如果不加volatile关键字,编译器可能会对bRunning_进行一定程度的优化,从而导致程序的行为出现意外的错误。因此,在多线程程序中,如果一个变量会被多个线程访问并修改,应该使用volatile关键字来修饰它。
Java中怎么理解volition关键字
volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
使用volition关键字增加了实例变量在多个线程间的可见性。但volition有个致命的缺点就是不支持原子性。
下面将volition和synchronized关键字进行一下比较:
1.volition是线程同步间的轻量级实现,所以volition性能肯定比synchronized性能好,volition只能修饰变量。
2.多线程访问volition不会发生阻塞,而synchronized会阻塞。
3.volition能保证数据的可见性,而不能保证原子性;而synchronized既可以保证原子性,也可以间接保证可见性。
4.再次强调,关键字volition解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
线程安全包含原子性和可见性两个方面,java的同步机制都是围绕这两个方面来却保线程安全的。
关键字volition主要使用的场合是在多个线程中可以感知共享变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量可以获取最新值使用。
关键字volition提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样保证了数据的可见性。
但是要注意,如果代码中有i++,也就是i=i+1时,这样的操作不是一个原子操作,也就是时非线程安全的。具体可以了解下i++的实际意义;
①从内存中读取变量i
②计算i的值
③将i的值写到内存中
加如两个线程同时执行到这段代码,那有可能就会出现脏数据,解决办法就是加synchronized字。
其实除了用synchronized,还可以用原子类解决。
这样可以代替i++,还不要加同步锁。
另外要说下synchronized关键字也能确保数据可见性。
最后学习多线程八字真经“外练互斥,内修可见”。
volatile关键字的使用场景
1.使用volatile白能量作为状态标志。在该场景中,应用程序的某个状态由一个线程设置,其他线程会读取该状态并作为下一步计算依据。这是适用volatile变量作为同步机制的好处是一个线程能够“通知”另外一个线程某个事件的发生,而这些线程有无需因此而使用锁,避免了锁的开销和相关问题。 2.使用volatile保障可见性。 3.使用volatile代替锁。当多个线程共享一个变量(而非一组变量)时,通常需要使用锁来保障对这些变量的更新操作的原子性,以避免数据不一致。利用volatile关键字写的原子性,将这一组状态变量封装成一个对象,将更新操作通过新建对象并将该对象赋值给volatile变量来实现。 4.实现简易版读写锁。通过volatile变量和锁的混合使用实现;锁保障写操作的原子性,volatile保证读操作的可见性。但这种读写锁允许线程可以读取到共享变量的非最新值。 public class Counter{ private volatile long count = 0; public long value(){ return count; } public void increment{ synchorized(this){ count++; } } }
java里volatile关键字有什么特性
Java语言中关键字 volatile 被称作轻量级的 synchronized,与synchronized相比,volatile编码相对简单且运行的时的开销较少,但能够正确合理的应用好 volatile 并不是那么的容易,因为它比使用锁更容易出错,接下来本文主要介绍 volatile 的使用准则,以及使用过程中需注意的地方。
为何使用volatile?
(1)简易性:在某些需要同步的场景下使用volatile变量要比使用锁更加简单
(2)性能:在某些情况下使用volatile同步机制的性能要优于锁
(3)volatile操作不会像锁一样容易造成阻塞
volatile特性
(1)volatile 变量具有 synchronized 的可见性特性,及如果一个字段被声明为volatile,java线程内存模型确保所有的线程看到这个变量的值是一致的
(2)禁止进行指令重排序
(3)不保证原子性
注:
① 重排序:重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段
② 原子性:不可中断的一个或一系列操作
③ 可见性:锁提供了两种主要特性:互斥和可见性,互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的。
volatile的实现原理
如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,该Lock指令会使这个变量所在缓存行的数据回写到系统内存,根据缓存一致性协议,每个处理器都会通过嗅探在总线上传输的数据来检查自己缓存的值是否已过期,当处理器发现自己的缓存行对应的地址被修改,就会将当前处理器的缓存行设置成无效状态,在下次访问相同内存地址时,强制执行缓存行填充。
正确使用volatile的场景
volatile 主要用来解决多线程环境中内存不可见问题。对于一写多读,是可以解决变量同步问题,但是如果多写,就无法解决线程安全问题。如:
1、不适合使用volatile的场景(非原子性操作)
(1)反例
private static volatile int nextSerialNum = 0;
public static long generateSerialNum() {
return nextSerialNum++;
}
这个方法的目的是要确保每次调用都返回不同的自增值,然而结果并不理想,问题在于增量操作符(++)不是原子操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,如果第二个线程在第一个线程读取旧值和写回新值期间读取这个域,第二个线程与第一个线程就会读取到同一个值。
(2)正例
其实面对上面的反例场景可以使用JDK1.5 java.util.concurrent.atomic中提供的原子包装类型来保证原子性操作
private static AtomicInteger nextSerialNum = new AtomicInteger(0);
public static long generateSerialNum() {
return nextSerialNum.getAndIncrement();
}
2、适合使用volatile的场景
在日常工作当中volatile大多被在状态标志的场景当中,如:
要通过一个线程来终止另外一个线程的场景
(1)反例
private static boolean stopThread;
public static void main(String args) throws InterruptedException {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (!stopThread) {
i++;
}
}
});
th.start();
TimeUnit.SECONDS.sleep(2);
stopThread = true;
}
运行后发现该程序根本无法终止循环,原因是,java语言规范并不保证一个线程写入的值对另外一个线程是可见的,所以即使主线程main函数修改了共享变量stopThread状态,但是对th线程并不一定可见,最终导致循环无法终止。
(2)正例
private static volatile boolean stopThread;
public static void main(String args) throws InterruptedException {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (!stopThread) {
i++;
}
}
});
th.start();
TimeUnit.SECONDS.sleep(2);
stopThread = true;
}
通过使用关键字volatile修饰共享变量stopThread,根据volatile的可见性原则可以保证主线程main函数修改了共享变量stopThread状态后对线程th来说是立即可见的,所以在两秒内线程th将停止循环。
volatile关键字在Java中有什么作用
volatile 是把变量标识为“变化中的”。意思是这个变量即使在(主线程)没有任何存取操作的情况下也可能在(被其他线程)变化。写上提醒注意线程安全。Java 1.4及之前版本加了这个的变量也没有同步安全。Java 5以后加了volatile后会在读取方面有同步安全。