平时在阅读jdk源码的时候,经常看到源码中有写变量被volatile关键字修饰,但是却不是十分清除这个关键字到底有什么用处,现在终于弄清楚了,那么我就来讲讲这个volatile到底有什么用吧。
当一个变量被定义为volatile之后,就可以保证此变量对所有线程的可见性,即当一个线程修改了此变量的值的时候,变量新的值对于其他线程来说是可以立即得知的。可以理解成:对volatile变量所有的写操作都能立刻被其他线程得知。但是这并不代表基于volatile变量的运算在并发下是安全的,因为volatile只能保证内存可见性,却没有保证对变量操作的原子性。比如下面的代码:
/**
* 发起20个线程,每个线程对race变量进行10000次自增操作,如果代码能够正确并发,
* 则最终race的结果应为200000,但实际的运行结果却小于200000。
*
* @author Colin Wang
*
*/
public class VolatileTest {
public static volatile int race = 0;
public static void increase() {
race++;
}
private static final int THREADS_COUNT = 20;
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_COUNT];
for (int i = 0; i < THREADS_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increase();
}
}
});
threads[i].start();
}
while (Thread.activeCount() > 1)
Thread.yield();
System.out.println(race);
}
}
这便是因为race++操作不是一个原子操作,导致一些线程对变量race的修改丢失。若要使用volatale变量,一般要符合以下两种场景:
- 变量的运算结果并不依赖于变量的当前值,或能够保证只有单一的线程修改变量的值。
- 变量不需要与其他的状态变量共同参与不变约束。
使用volatile变量还可以禁止JIT编译器进行指令重排序优化,这里使用单例模式来举个例子:
/**
* 单例模式例程一
*
* @author Colin Wang
*
*/
public class Singleton_1 {
private static Singleton_1 instance = null;
private Singleton_1() {
}
public static Singleton_1 getInstacne() {
/*
* 这种实现进行了两次instance==null的判断,这便是单例模式的双检锁。
* 第一次检查是说如果对象实例已经被创建了,则直接返回,不需要再进入同步代码。
* 否则就开始同步线程,进入临界区后,进行的第二次检查是说:
* 如果被同步的线程有一个创建了对象实例, 其它的线程就不必再创建实例了。
*/
if (instance == null) {
synchronized (Singleton_1.class) {
if (instance == null) {
/*
* 仍然存在的问题:下面这句代码并不是一个原子操作,JVM在执行这行代码时,会分解成如下的操作:
* 1.给instance分配内存,在栈中分配并初始化为null
* 2.调用Singleton_1的构造函数,生成对象实例,在堆中分配
* 3.把instance指向在堆中分配的对象
* 由于指令重排序优化,执行顺序可能会变成1,3,2,
* 那么当一个线程执行完1,3之后,被另一个线程抢占,
* 这时instance已经不是null了,就会直接返回。
* 然而2还没有执行过,也就是说这个对象实例还没有初始化过。
*/
instance = new Singleton_1();
}
}
}
return instance;
}
}
/**
* 单例模式例程二
*
* @author Colin Wang
*
*/
public class Singleton_2 {
/*
* 为了避免JIT编译器对代码的指令重排序优化,可以使用volatile关键字,
* 通过这个关键字还可以使该变量不会在多个线程中存在副本,
* 变量可以看作是直接从主内存中读取,相当于实现了一个轻量级的锁。
*/
private volatile static Singleton_2 instance = null;
private Singleton_2() {
}
public static Singleton_2 getInstacne() {
if (instance == null) {
synchronized (Singleton_2.class) {
if (instance == null) {
instance = new Singleton_2();
}
}
}
return instance;
}
}
变量在有了volatile修饰之后,对变量的修改会有一个内存屏障的保护,使得后面的指令不能被重排序到内存屏障之前的位置。volalite变量的读性能与普通变量类似,但是写性能要低一些,因为它需要插入内存屏障指令来保证处理器不会发生乱序执行。即便如此,大多数场景下volatile的总开销仍然要比锁低,所以volatile的语义能满足需求时候,选择volatile要优于使用锁。
分享到:
相关推荐
本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...
本文将深入探讨Java线程的核心概念、API以及在实际开发中的应用,旨在帮助你理解和掌握这一关键技能。 首先,我们需要了解什么是线程。在单核CPU系统中,线程是操作系统调度的基本单位,而在多核CPU系统中,每个...
在《java线程与并发实践编程》中,作者Jeff Friesen可能还会深入讨论线程池的配置策略、死锁和活锁的预防、线程性能分析与调优,以及Java内存模型(JMM)和线程通信模型(如wait()、notify()、notifyAll())等内容。...
通过学习《JAVA线程第三版》,开发者可以深入理解Java并发编程的核心概念和技术,掌握在实际项目中设计和管理并发程序的方法,提升软件开发的效率和质量。书中的实例和最佳实践对于任何希望提升并发编程技能的Java...
《Java多线程编程实战指南-核心篇》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握在Java环境中创建、管理和同步线程的核心技术。Java的多线程能力是其强大之处,使得开发者能够在同一时间执行多个任务,提高...
本篇文章将深入分析Volatile的实现原理,结合`LinkedTransferQueue`和`TransferQueue`这两个与并发相关的Java源码,探讨其在多线程环境中的应用。 首先,我们需要理解Java内存模型(JMM,Java Memory Model),它是...
### Java线程教程知识点梳理 #### 一、教程概述 - **目标读者**: 本教程主要面向具备丰富Java基础知识但缺乏多线程编程经验的学习者。 - **学习成果**: 学习者能够掌握编写简单的多线程程序的能力,并能够理解和...
2. **线程同步**:为了解决多线程中的数据安全问题,Java提供了多种同步机制,如`synchronized`关键字、`volatile`变量、`Lock`与`Condition`接口、`ReentrantLock`等。这些内容在书中会有详细讲解,包括它们的工作...
4. **线程优先级与守护线程**:Java线程有优先级之分,可以影响调度,但实际效果取决于操作系统。守护线程(Daemon Thread)是一种特殊类型的线程,当它是系统中唯一运行的线程时,JVM会自动退出。 5. **并发集合与...
Java线程允许程序中的不同部分同时运行,这在处理大量I/O操作、网络通信或者需要进行复杂计算时尤其有用。本资料包聚焦于Java线程实践练习,旨在加深对Java编程及并发的理解。 一、Java线程基础 Java线程可以通过两...
《Java线程——第三版》是一本专注于Java多线程编程的专业书籍,旨在帮助开发者深入理解和熟练掌握Java中的并发处理技术。多线程是现代软件开发中的重要概念,尤其是在服务器端应用、分布式系统以及高性能计算等领域...
通过以上内容的学习,读者可以深入了解Java线程的高级使用方法,掌握如何在Java程序中高效地管理和控制线程,以及如何解决多线程环境下常见的问题。这对于开发高性能、高可用性的Java应用至关重要。
《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,提升系统效率。这个资源包含的"SimpleThread"源码很可能是对...通过学习和分析这个源码,你可以深入理解Java多线程编程的核心概念和实践技巧。
### 深入Java多线程与并发编程 在当今高度发展的信息技术领域中,随着硬件技术的进步和软件架构设计的复杂化,多线程与并发编程成为提高程序执行效率、增强系统性能的关键技术之一。本篇文章将围绕Java多线程与并发...
"Java线程案例"这个主题深入探讨了如何在Java中创建、管理和同步线程,这对于理解和掌握多线程编程至关重要。 线程的创建在Java中有多种方式: 1. 继承`Thread`类:创建一个新的类,继承自`Thread`类,重写`run()`...
Java中的volatile关键字是一个关键的同步机制,它在多线程编程中扮演着重要的角色。在面试和技术讨论中,volatile经常成为焦点,但其工作原理却常常引发争议。本文将从JVM、C++以及汇编语言的角度深入探讨volatile的...
2. **线程同步**:为了解决多线程环境下的数据一致性问题,Java提供了多种同步机制,如synchronized关键字、volatile变量、java.util.concurrent包下的锁(如ReentrantLock)以及并发工具类(如Semaphore、...
Java多线程是Java编程中的核心概念,尤其在并发编程领域,它的重要性不言而喻。这个名为"java多线程源码,仅供参考...通过分析和运行这个示例,我们可以直观地看到多线程在实际场景中的应用,加深对Java多线程的理解。
Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...