温馨提示:这篇文章已超过410天没有更新,请注意相关的内容是否还可用!
摘要:本文将深入探讨Java注解机制在并发编程中的应用,尤其关注如何解决时间相关的难题。我们将解密Happens-Before的神秘面纱,让读者了解如何通过Java的内存模型确保并发操作的正确执行顺序,从而避免多线程环境下的数据不一致问题。通过本文,读者将更好地理解Java注解如何助力并发编程,提高代码质量和性能。
简介
为什么需要happens-before原则:主要是由于Java内存模型为了提高CPU效率,通过工作内存(Cache)代替了主内存,修改临界资源会更新work memory但并不一定立刻刷到主存中,JMM会将编写的代码编译后执行,但编译器生成的指令顺序可能与源码顺序不完全一致,处理器可能采用乱序或并行方式执行指令,因为在JVM中只要程序的最终结果一致,这种重排序是允许的,并且处理器还有本地缓存,当结果存储在本地缓存中时,其他线程可能无法看到结果,除此之外,缓存提交到主内存的顺序也可能会变化,在多线程环境下,可能会产生不同的结果,针对以上问题,JMM给出了happens-before通用的规则。
为了保证java内存模型中的操作顺序,JMM为程序中的所有操作定义了一个顺序关系,这个顺序叫做Happens-Before,要想保证操作B看到操作A的结果,不管A和B是在同一线程还是不同线程,那么A和B必须满足Happens-before的关系,如果两个操作不满足happens-before的关系,那么JVM可以对他们任意重排序。
两个操作间具有happens-before关系,并不意味着前一个操作必须在后一个操作之前执行,happens-before仅仅要求前一个操作对后一个操作可见。
volatile 关键字是践行happens-before原则的关键字之一,happens-before指的是线程接收其他线程修改共享变量的消息与该线程读取共享变量的先后关系,volatile变量规则:对一个volatile的写操作,happens-before于任意后续对这个volatile变量的读操作。
从Java源代码到最终实际执行的指令序列,会经历以下三种重排序:源代码优化重排序、指令级并行的重排序和内存系统的重排序,其中涉及到的具体规则如下:
【程序顺序规则】:如果在程序中操作A在操作B之前,那么在同一个线程中操作A将会在操作B之前执行,这里的操作A在操作B之前执行是指在单线程环境中,虽然虚拟机会对相应的指令进行重排序,但是最终的执行结果跟按照代码顺序执行是一样的,虚拟机只会对不存在依赖的代码进行重排序。
【监视器锁规则】:监视器上的解锁操作必须在同一个监视器上面的加锁操作之前执行,如果线程解锁了monitor a,接着线程锁定a,那么线程解锁a之前的写操作都对线程可见(线程可以是同一个线程)。
【volatile变量规则】:对volatile变量的写入操作必须在对该变量的读操作之前执行,原子变量和volatile变量在读写操作上面有着相同的语义,如果线程写入volatile变量v(临界资源),接着线程读取了v,那么线程写入v及之前的写操作都对线程可见,传递性规则:如果操作A在操作B之前执行并且操作B在操作C之前执行,那么操作A必须在操作C之前执行,这意味着如果两个或多个操作之间存在一个有序关系链,那么这些操作的顺序将按照链的顺序进行,同时还有其他规则如线程启动规则、线程结束规则等也适用于多线程环境下的同步问题,这些规则共同构成了happens-before原则的基础框架和核心思想,接下来通过一个单例模式的案例来进一步说明happens-before原则的应用场景和重要性,在单例模式中由于涉及到多线程并发访问共享资源的问题如果不考虑happens-before原则可能会导致出现多个实例的情况从而破坏单例模式的正确性通过引入synchronized关键字和volatile关键字来保证操作的原子性和可见性从而确保单例模式的正确实现同时通过对as-if-serial语义的讲解进一步说明了happens-before原则的作用和意义最后通过一个关于volatile关键字的案例进一步巩固了happens-before原则的应用和理解同时给出了相关的图示说明帮助读者更好地理解文章内容,二、as-if-serial语义 as-if-serial语义:不管怎么重排序只要单线程程序的执行结果不能被改变编译器runtime和处理器都必须遵守as-if-serial语义,所以编译器和处理器不会对存在数据依赖关系的操作做重排序因为这种重排序会改变执行结果,但是如果在单线程程序中控制依赖的操作重排序不会改变程序的执行结果而在多线程程序中控制依赖的操作重排序可能会改变程序的执行结果本质上来说Happens-before关系和as-if-serial语义是一回事都是为了在不改变程序执行结果的前提下尽可能地提高程序执行的并行度只不过后者只能作用在单线程而前者可以作用在正确同步的多线程环境下: as-if-serial语义保证单线程内程序的执行结果不被改变Happens-before关系保证正确同步的多线程程序的执行结果不被改变,as-if-serial语义给编写单线程程序的程序员创造了一个幻境:单线程程序是按程序的顺序来执行的,Happens-before关系给编写正确同步的多线程程序的程序员创造了一个幻境:正确同步的多线程程序是按Happens-before指定的顺序来执行的,三、案例 VolitileExample类中有一个整型变量a和一个volatile类型的布尔型变量flag在reader方法中先判断flag是否为true然后读取a的值在writer方法中先设置a的值为10然后设置flag为true假设Thread A执行writer方法后Thread B执行reader方法
还没有评论,来说两句吧...