- 浏览: 1090460 次
文章分类
- 全部博客 (379)
- S2SH (16)
- stuts2 (0)
- java语言 (81)
- JSP (17)
- <html>元素 (11)
- javaweb (4)
- web容器 (3)
- ext (23)
- javaScript (48)
- ant (1)
- liferay (1)
- sql (9)
- css (42)
- 浏览器设置 (3)
- office_world (1)
- eclipse (4)
- 其它 (28)
- 操作系统 (5)
- android (6)
- Struts2 (11)
- RegEx (3)
- mysql (5)
- BigDATA (1)
- Node.js (1)
- Algorithm (10)
- Apache Spark (1)
- 数据库 (5)
- linux (2)
- git (1)
- Adobe (3)
- java语言,WebSocket (1)
- Maven (3)
- SHELL (1)
- XML (2)
- 数学 (2)
- Python (2)
- Java_mysql (1)
- ReactJS (6)
- 养生 (4)
- Docker (1)
- Protocols (3)
- java8 (2)
- 书籍 (1)
- Gradle (2)
- AngularJS (5)
- SpringMVC (2)
- SOAP (1)
- BootstrapCSS (1)
- HTTP协议 (1)
- OAuth2 (1)
最新评论
-
Lixh1986:
Java并发编程:自己动手写一把可重入锁https://blo ...
Java之多线程之Lock与Condition -
Lixh1986:
http://win.51apps.com.cn/https: ...
temp -
ztwsl:
不错,支持很好
HttpServletRequest和ServletRequest的区别 -
guodongkai:
谢谢您能将知识精华汇编总结,让初学者们从原理中学会和提高。
javaScript之function定义 -
kangwen23:
谢谢了,顶顶
struts2中的ValueStack学习
一、什么是 volatile ?
为了更好地了解Java中的volatile关键字,您将必须对Java内存模型中的变量发生的优化有所了解。假设您在代码中声明了一个名为 test 的变量。您会认为 test 变量将仅存储在RAM中,并且所有线程都将从那里读取测试变量的值。但是,为了使处理更快,处理器会将变量的值保存在其缓存中。在那种情况下,仅当高速缓存和内存之间发生同步时,对值的任何更改才会写回到主内存。
这将在多个线程正在读取或写入共享变量的地方引起问题。如果我们以在多个线程中使用的 test 变量为例,则可能出现以下情况:一个线程对仍存储在高速缓存中的 test 变量进行了更改,而另一个线程试图从主内存中读取测试变量的值 。这将导致内存和高速缓存数据不一致错误,因为不同的线程将读取/写入不同的测试变量值。
二、如何声明 volatile ?
将变量声明为 volatile 可确保始终从主存储器读取变量的值。 因此,在Java中将字段声明为volatile 可以提供线程可见性。从而确保每次对volatile字段进行都写操作,都会早于随后读取该字段的操作,即:(当前线程的)写操作对随后的(其它线程的)读操作都是可见的。
我们在上面看到的问题是因为 volatile 字段不会发生CPU缓存的值,因为可以保证线程1对volatile变量所做的更新始终对线程2可见。
三、 volatile 使用示例
Java中volatile关键字最常见的用法之一是声明为volatile的布尔状态标志,该标志指示事件的完成,以便另一个线程可以启动。
首先让我们看看如果在这种情况下不使用volatile会发生什么。
OUTPUT
运行此代码后,您会看到第一个线程显示i直到2000的值,然后并更改状态标志。但是第二个线程不会打印消息“Start other processing ”,并且程序不会终止。 由于在while循环中的线程2中经常访问flag变量,因此编译器可以通过将flag的值放在缓存寄存器中来进行优化,然后它将继续测试循环条件(while(!flag)),而无需向主存储器中读取其中的值。
现在,如果您更改布尔变量标志并将其标记为volatile,这将确保一个线程对共享变量所做的更改对其他线程可见。
OUTPUT:结果正确
四、 volatile 受变量声明的顺序的影响
当线程读取一个volatile变量时,它不仅会看到对volatile的最新更改,还会看到导致更改的代码的副作用。 这也称为(happens-before-extended-guarantee),由Java 5中的volatile 关键字提供。
例如,如果线程T1在更新volatile变量之前更改了其他变量,则线程T2也将获得那些在线程T1中更新volatile变量之前已更改的变量的更新变量。
这将我们带到可能在编译时发生的重新排序以优化代码的地步。 只要不改变语义,就可以对代码语句进行重新排序。
由于var3是 volatile 的,由于 happens-before extended guarantee,因此var1和var2的更新值也将被写入主内存,并且对其他线程可见。
如果将这些语句重新排序以进行优化怎么办。
现在,变量var1和var2的值在 volatile 变量var3更新后更新。 因此,这些变量var1和var2的更新值可能不可用于其他线程。
这就是为什么如果在更新其他变量之后对 volatile 变量进行读取或写入,则不允许重新排序的原因。
五、 volatile 只能保证 可见性,不能保证原子性
在只有一个线程正在写入变量而其他线程仅在读取的情况下(如在状态标志的情况下),volatile有助于正确查看变量值。 但是,如果许多线程正在读取和写入共享变量的值,那么volatile是不够的。 在那种情况下,由于竞争条件,线程可能仍会得到错误的值。
让我们用一个Java示例来说清楚,其中有一个SharedData类,其对象在线程之间共享。 在SharedData类中,计数器变量被标记为volatile。 创建了四个线程,它们使计数器递增,然后显示更新的值。 由于存在竞争条件,线程可能仍会获得错误的值。 请注意,您也可以在几次运行中获得正确的值。
OUTPUT
六、 volatile 要点总结
在Java中volatile关键字只能与不带的方法和类变量使用。
标记为volatile的变量可确保不缓存该值,并且对volatile变量的更新始终在主内存中进行。
volatile 也保证了报表的重新排序不会发生这样的挥发性提供的之前发生延长的保证下volatile变量的更新之前更改其他变量也被写入主存储器和可见的其他线程。
volatile 确保仅可见性而不是原子性。
如果 final 变量也声明为 volatile,则是编译时错误。
使用 volatile 比使用 Lock 便宜。
-
Refer: https://knpcode.com/java/multi-threading/volatile-keyword-in-java/
-
为了更好地了解Java中的volatile关键字,您将必须对Java内存模型中的变量发生的优化有所了解。假设您在代码中声明了一个名为 test 的变量。您会认为 test 变量将仅存储在RAM中,并且所有线程都将从那里读取测试变量的值。但是,为了使处理更快,处理器会将变量的值保存在其缓存中。在那种情况下,仅当高速缓存和内存之间发生同步时,对值的任何更改才会写回到主内存。
这将在多个线程正在读取或写入共享变量的地方引起问题。如果我们以在多个线程中使用的 test 变量为例,则可能出现以下情况:一个线程对仍存储在高速缓存中的 test 变量进行了更改,而另一个线程试图从主内存中读取测试变量的值 。这将导致内存和高速缓存数据不一致错误,因为不同的线程将读取/写入不同的测试变量值。
二、如何声明 volatile ?
将变量声明为 volatile 可确保始终从主存储器读取变量的值。 因此,在Java中将字段声明为volatile 可以提供线程可见性。从而确保每次对volatile字段进行都写操作,都会早于随后读取该字段的操作,即:(当前线程的)写操作对随后的(其它线程的)读操作都是可见的。
我们在上面看到的问题是因为 volatile 字段不会发生CPU缓存的值,因为可以保证线程1对volatile变量所做的更新始终对线程2可见。
三、 volatile 使用示例
Java中volatile关键字最常见的用法之一是声明为volatile的布尔状态标志,该标志指示事件的完成,以便另一个线程可以启动。
首先让我们看看如果在这种情况下不使用volatile会发生什么。
public class VolatileDemo { private static boolean flag = false; public static void main(String[] args) { // Thread-1 new Thread(new Runnable(){ @Override public void run() { for (int i = 1; i <= 2000; i++){ System.out.println("value - " + i); } // changing status flag flag = true; System.out.println("status flag changed " + flag ); } }).start(); // Thread-2 new Thread(new Runnable(){ @Override public void run() { int i = 1; while (!flag){ i++; } System.out.println("Start other processing " + i); } }).start(); } }
OUTPUT
.... .... value - 1997 value - 1998 value - 1999 value - 2000 status flag changed true
运行此代码后,您会看到第一个线程显示i直到2000的值,然后并更改状态标志。但是第二个线程不会打印消息“Start other processing ”,并且程序不会终止。 由于在while循环中的线程2中经常访问flag变量,因此编译器可以通过将flag的值放在缓存寄存器中来进行优化,然后它将继续测试循环条件(while(!flag)),而无需向主存储器中读取其中的值。
现在,如果您更改布尔变量标志并将其标记为volatile,这将确保一个线程对共享变量所做的更改对其他线程可见。
private static volatile boolean flag = false;
OUTPUT:结果正确
.... .... value - 1997 value - 1998 value - 1999 value - 2000 status flag changed true Start other processing 68925258
四、 volatile 受变量声明的顺序的影响
当线程读取一个volatile变量时,它不仅会看到对volatile的最新更改,还会看到导致更改的代码的副作用。 这也称为(happens-before-extended-guarantee),由Java 5中的volatile 关键字提供。
例如,如果线程T1在更新volatile变量之前更改了其他变量,则线程T2也将获得那些在线程T1中更新volatile变量之前已更改的变量的更新变量。
这将我们带到可能在编译时发生的重新排序以优化代码的地步。 只要不改变语义,就可以对代码语句进行重新排序。
private int var1; private int var2; private volatile int var3; public void calcValues(int var1, int var2, int var3){ this.var1 = 1; this.var2 = 2; this.var3 = 3; }
由于var3是 volatile 的,由于 happens-before extended guarantee,因此var1和var2的更新值也将被写入主内存,并且对其他线程可见。
如果将这些语句重新排序以进行优化怎么办。
this.var3 = 3; this.var1 = 1; this.var2 = 2;
现在,变量var1和var2的值在 volatile 变量var3更新后更新。 因此,这些变量var1和var2的更新值可能不可用于其他线程。
这就是为什么如果在更新其他变量之后对 volatile 变量进行读取或写入,则不允许重新排序的原因。
五、 volatile 只能保证 可见性,不能保证原子性
在只有一个线程正在写入变量而其他线程仅在读取的情况下(如在状态标志的情况下),volatile有助于正确查看变量值。 但是,如果许多线程正在读取和写入共享变量的值,那么volatile是不够的。 在那种情况下,由于竞争条件,线程可能仍会得到错误的值。
让我们用一个Java示例来说清楚,其中有一个SharedData类,其对象在线程之间共享。 在SharedData类中,计数器变量被标记为volatile。 创建了四个线程,它们使计数器递增,然后显示更新的值。 由于存在竞争条件,线程可能仍会获得错误的值。 请注意,您也可以在几次运行中获得正确的值。
public class VolatileDemo implements Runnable { SharedData obj = new SharedData(); public static void main(String[] args) { VolatileDemo vd = new VolatileDemo(); new Thread(vd).start(); new Thread(vd).start(); new Thread(vd).start(); new Thread(vd).start(); } @Override public void run() { obj.incrementCounter(); System.out.println("Counter for Thread " + Thread.currentThread().getName() + " " + obj.getCounter()); } } class SharedData{ public volatile int counter = 0; public int getCounter() { return counter; } public void incrementCounter() { ++counter; } }
OUTPUT
Counter for Thread Thread-0 1 Counter for Thread Thread-3 4 Counter for Thread Thread-2 3 Counter for Thread Thread-1 3
六、 volatile 要点总结
在Java中volatile关键字只能与不带的方法和类变量使用。
标记为volatile的变量可确保不缓存该值,并且对volatile变量的更新始终在主内存中进行。
volatile 也保证了报表的重新排序不会发生这样的挥发性提供的之前发生延长的保证下volatile变量的更新之前更改其他变量也被写入主存储器和可见的其他线程。
volatile 确保仅可见性而不是原子性。
如果 final 变量也声明为 volatile,则是编译时错误。
使用 volatile 比使用 Lock 便宜。
-
Refer: https://knpcode.com/java/multi-threading/volatile-keyword-in-java/
-
发表评论
-
java 将文件夹所有的文件合并到指定的文件夹下
2020-06-30 19:17 974场景:将文件夹所有的文件合并到指定的文件夹下 另外:如果想效 ... -
多线程-线程池的四种创建方式
2020-04-01 18:38 406多线程-线程池的四种创建方式 https://blog.cs ... -
Java基础之:nio
2019-11-13 15:38 409一、理论讲解: 史上最强Java NIO入门:担心从入门到放弃 ... -
Java 分布式之:RPC 基本概念
2019-11-13 15:07 398转载: https://www.jianshu.com/p/ ... -
POI实现excell批注背景图片(仿html浮窗显示图片)
2019-10-21 08:17 597POI实现excell批注背景图片(仿html浮窗显示图片) ... -
Java之设计模式之 Observer 观察者
2019-07-04 17:21 969观察者设计模式 Java 已经实现了该模式,并且提供了使用类 ... -
HashMap, LinkedHashMap and TreeMap
2019-03-01 11:04 622https://stackoverflow.com/a/177 ... -
Java lib 操作 excel 插入图片
2019-01-19 12:46 836https://poi.apache.org/componen ... -
数据库连接池C3P0
2018-05-29 16:50 808一、名字的由来 很多 ... -
Java8之集合(Collection)遍历 forEach()、stream()
2018-05-29 14:39 20655package java8.collections; ... -
Junit Vs main on "java.util.concurrent.Executors"
2017-11-10 16:44 730Same code with different result ... -
Java之大数据学习路线
2017-11-03 10:08 5671三个月大数据研发学习 ... -
Java中创建对象的5种方式
2017-10-26 14:21 802一、Java之5种创建对象的方式 ————————————— ... -
Log4j和Slf4j的比较
2017-06-23 12:41 1358一直搞不清 Log4j 和 SLF4j 的关系。今天才若有所 ... -
Java之Java7新特性之try资源句式
2017-04-20 14:58 5337Java之Java7新特性之try资源句式 一、【try资源 ... -
Java之 java.util.concurrent 包之ExecutorService之submit () 之 Future
2017-03-04 21:27 3769一、如何使用 ExecutorService.submit() ... -
Java之 java.util.concurrent 包之Executor与ExecutorService
2017-03-04 21:18 2638一、问题: execute() 与 submit() 的区别? ... -
JAVAEE之单用户登录
2017-02-05 11:55 1030单用户登录是系统中数据一直性的解决方案之一。 问题背景: 试 ... -
Java之多线程之线程池之线程重复使用
2017-02-04 13:33 5520一、问题背景 在使用多线程时,如果要开启一个任务,则就需要新 ... -
Java之语法之方法调用之地址传值之空对象(null)
2017-01-26 14:05 3232一、问题: public void test ...
相关推荐
Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、单任务延迟连接池 六、自定义线程池 Java线程:新特征-有返回值的线程...
本资源为您提供了关于 Java 并发编程理论基础的精讲,涵盖了多线程编程的核心概念、基本原理以及在 Java 中的应用。通过深入学习,您将建立坚实的并发编程基础,能够更好地理解和应对多线程编程中的挑战。 并发编程...
hashmap实现原理,java基础笔记,java基础面试全集,java里的volatile关键字详解,jvm垃圾回收,MySQL索引背后的数据结构及算法原理,MySQL性能优化的最佳21条经验,MySQL中的锁(表锁、行锁),Redis的优点和5种...
synchronize 关键字原理 多线程的三大核心 对锁的一些认知 ReentrantLock 实现原理 ConcurrentHashMap 的实现原理 线程池原理 深入理解线程通信 交替打印奇偶数 JVM Java 运行时内存划分 类加载机制 OOM 分析 垃圾...
synchronize 关键字原理 多线程的三大核心 对锁的一些认知 ReentrantLock 实现原理 ConcurrentHashMap 的实现原理 线程池原理 深入理解线程通信 交替打印奇偶数 JVM Java 运行时内存划分 类加载机制 OOM 分析 垃圾...
synchronize 关键字原理 多线程的三大核心 对锁的一些认知 ReentrantLock 实现原理 ConcurrentHashMap 的实现原理 线程池原理 深入理解线程通信 交替打印奇偶数 JVM Java 运行时内存划分 类加载机制 OOM 分析 垃圾...
无论是工作学习,不断的总结是必不可少的。只有不断的总结,发现问题,弥补不足,才能长久的进步!!Java学习更是如此,知识点总结目录如下: ...volatile详解 337 Java 8新特性 347 Java 性能优化 362
volatile (关键字) 不稳定的['vɒlәtail] while (关键字) 循环语句。 当...的时候 [hwail] ORACLE_SID=oral10g\ --变局部变量 export ORACLE_SID --变全局变量 unset ORACLE_SID --卸载环境变量 ORACLE_HOME=...
83_AtomicIntegerFieldUpdater实例演练与volatile关键字分析;84_Netty引用计数注意事项与内存泄露检测方式;85_Netty编解码器剖析与入站出站处理器详解;86_Netty自定义编解码器与TCP粘包拆包问题;87_Netty编解码...
Netty引用计数的实现机制与自旋锁的使用技巧 82_Netty引用计数原子更新揭秘与AtomicIntegerFieldUpdater深度剖析 83_AtomicIntegerFieldUpdater实例演练与volatile关键字分析 84_Netty引用计数注意事项与内存泄露...
25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................
83_AtomicIntegerFieldUpdater实例演练与volatile关键字分析 84_Netty引用计数注意事项与内存泄露检测方式 85_Netty编解码器剖析与入站出站处理器详解 86_Netty自定义编解码器与TCP粘包拆包问题 87_Netty编解码器...
【JVM】JAVA编译原理和JVM原理 42 【JVM】Java内存模型 44 【JVM】jvm内存模型 45 主内存与工作内存 45 内存间交互操作 46 重排序 48 【JVM】内存泄漏 49 【JVM】java虚拟机的区域如何划分,每一个区的动能? 49 ...
第83讲:AtomicIntegerFieldUpdater实例演练与volatile关键字分析 第84讲:Netty引用计数注意事项与内存泄露检测方式 第85讲:Netty编解码器剖析与入站出站处理器详解 第86讲:Netty自定义编解码器与TCP粘包拆包...
│ 高并发编程第二阶段10讲、volatile关键字深入详解.mp4 │ 高并发编程第二阶段11讲、volatile关键字总结.mp4 │ 高并发编程第二阶段12讲、观察者设计模式介绍.mp4 │ 高并发编程第二阶段13讲、使用观察者设计...
│ 高并发编程第二阶段10讲、volatile关键字深入详解.mp4 │ 高并发编程第二阶段11讲、volatile关键字总结.mp4 │ 高并发编程第二阶段12讲、观察者设计模式介绍.mp4 │ 高并发编程第二阶段13讲、使用观察者设计...