Java提供了一种弱同步机制,即volatile变量,用来确保将变量的更新操作通知到其它线程,它是比synchronized关键字更轻的一种同步机制。在当前大多数处理器架构上,读取volatile变量只比读取非volatile变量的开销略高一些。
当一个变量被定义为volatile后,它具备两种特性,第一是保证此变量对所有线程的可见性,指当一个线程修改了这个变量的值,新值对其它线程来说是立即得知的,而普通变量不能做到这点,普通变量的值在线程间传递要通过主内存来完成,如线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成后再从主内存进行读取操作,新变量的值才会对主线程可见。虽然volatile变量对所有线程都是可见的,但是并不代表它在多线程并发环境下是安全的。
使用volatile变量时注意,volatile变量不足以确保递增操作的原子性,除非能确保只有一个线程对变量执行写操作。也就是声明为volatile的变量当前值与该变量以前的值相关,那么volatile变量将不起作用,即下列表达式都不是原子的:
n=n+1;
n++;
如下代码:
public class MyRunnable implements Runnable { public static volatile int n = 0; public void run() { for (int i = 0; i < 10; i++) { try { n = n + 1; Thread.sleep(10); } catch (Exception e) { // TODO: handle exception } } } } public class MainTest { public static void main(String[] args) throws Exception { Thread[] threads = new Thread[100]; // 创建100个线程 for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new MyRunnable()); } // 启动100个线程 for (int i = 0; i < threads.length; i++) { threads[i].start(); } // 让100个线程都执行完 for (int i = 0; i < threads.length; i++) { threads[i].join(); } System.out.println(MyRunnable.n); } }
上面代码,如果对n的操作是原子性的,则输出n=1000,但输出结果不到1000,说明对n的更新不是线程安全的。有人说n++的指令为iinc 1,1,是原子操作,但是把上面n=n+1改成n++后还是出现线程不同步。要想把上面代码改成线程同步,可以在对n的操作中添加synchronized关键字,如下:
synchronized (MyRunnable.class) { n = n + 1; }
只有当变量的值和自身的上一个值是无关的volatile关键字才有效,如n=m+1;所以当且仅当满足下面条件时才应该使用volatile变量:
- 对变量的写入操作不依赖变量的当前值,除非能确保只有单个线程更新该变量的值
- 该变量不与其它状态变量一起纳入不变性条件中
- 在访问该变量时不需要加锁
当一个线程被volatile修饰后,它将具备下面两种特性:
1、线程可见性:当一个线程被volatile修改后,无论是否加锁,其它线程都可以看到最新的修改,而普通变量做不到这一点;
2、禁止指令重新排序优化,普通的变量仅仅保证在该方法的执行过程中所有依赋值结果的地方都能获得正确的结果,而不能保证变量赋值操作的顺序与程序代码的执行顺序一致
看下面例子:
import java.util.concurrent.TimeUnit; public class ThreadStopExample { private static boolean stop; public static void main(String[] args) throws InterruptedException { Thread workThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stop) { i++; System.out.println(i); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } }); workThread.start(); TimeUnit.SECONDS.sleep(3); stop = true; } }
关于volatile更深入文章:聊聊并发(一)——深入分析Volatile的实现原理
相关推荐
主要介绍了Java多线程 volatile关键字详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Java线程:volatile关键字 Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:...
Java线程:volatile关键字 Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-...
volatile关键字相信了解Java多线程的读者都很清楚它的作用。volatile关键字用于声明简单类型变量,下面看一下为什么要慎重使用volatile关键字
volatile是JVM提供的一种最轻量级的同步机制,因为Java内存模型为volatile定义特殊的访问规则,使其可以实现Java内存模型中的两大特性...这篇文章主要介绍了Java多线程之volatile关键字及内存屏障,需要的朋友可以参考下
本文详细解读一下volatile关键字如何保证变量在多线程之间的可见性,对Java中volatile关键字实现原理感兴趣的朋友一起通过本文学习吧
线程安全、volatile关键字、原子性、并发包、死锁、线程池学习笔记
三、 volatile关键字 38 四、 使用synchronized关键字要注意以下四点 39 五、 关于同步和锁定的一些问题 41 Java线程:并发协作-线程的交互 47 Java线程:并发协作-生产者消费者模型 52 Java线程:并发协作-死锁 55 ...
在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候可以万事大吉。 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 ...
volatile 关键字是一个神秘的关键字,也许在 J2EE 上的 JAVA 程序员会了解多一点,但在 Android 上的 JAVA 程序员大多不了解这个关键字。只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把 volatile ...
4. Java多线程学习(三)volatile关键字 5. Java多线程学习(四)等待/通知(wait/notify)机制 6. Java多线程学习(五)线程间通信知识点补充 7. Java多线程学习(六)Lock锁的使用 8. Java多线程学习(七)...
本篇文章提供了20道高难度的Java多线程编程面试题及详细解析,旨在帮助开发者展示出卓越的并发编程能力。在当今高并发的应用场景下,对多线程编程的理解和应用是评估面试者的重要指标。通过这些高难度问题,您将全面...
Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制
Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、单任务延迟连接池 六、自定义线程池 Java线程:新特征-有返回值的线程...
Java 多线程与并发(5_26)-关键字_ volatile详解
第三部分详细、深入地介绍volatile关键字的语义,volatile关键字在Java中非常重要,可以说它奠定了Java核心并发包的高效运行,在这一部分中,我们通过实例展示了如何使用volatile关键字以及非常详细地介绍了Java内存...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
volatile关键字可以保证变量的可见性,当一个线程修改了volatile变量的值,新值对于其他线程来说是立即可见的,这样可以防止由于线程间的数据不一致导致的问题 Lock接口 Lock接口提供了比synchronized关键字更广泛的...