java线程之Happens before规则案例详解

目录
  • 正文
    • 案例1
    • 案例2
    • 案例3
    • 案例4
    • 案例5
    • 案例6
    • 案例7

正文

happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见.

案例1

线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见

    static int x;
    static Object m = new Object();

    new Thread(()->{
         synchronized(m) {
         x = 10;
         }
    },"t1").start();

    new Thread(()->{
         synchronized(m) {
         System.out.println(x);
         }
    },"t2").start();
/*
运行结果:
10
*/

案例2

线程对 volatile 变量的写,对接下来其它线程对该变量的读可见

    volatile static int x;
    new Thread(()->{
     x = 10;
    },"t1").start();

    new Thread(()->{
     System.out.println(x);
    },"t2").start();
/*
运行结果:
10
*/

案例3

线程 start 前对变量的写,对该线程开始后对该变量的读可见

static int x;
x = 10;
new Thread(()->{
 System.out.println(x);
},"t2").start();
/*
运行结果:
10
*/

案例4

线程结束前对变量的写,对其它线程得知它结束后的读可见(比如其它线程调用 t1.isAlive() 或 t1.join()等待 它结束)

static int x;
Thread t1 = new Thread(()->{
 x = 10;
},"t1");
t1.start();
t1.join();
System.out.println(x);
/*
运行结果:
10
*/

案例5

线程 t1 打断 t2(interrupt)前对变量的写,对于其他线程得知 t2 被打断后对变量的读可见(通过 t2.interrupted 或 t2.isInterrupted)

static int x;
public static void main(String[] args) {

     Thread t2 = new Thread(()->{
         while(true) {
             if(Thread.currentThread().isInterrupted()) {
             System.out.println(x);
             break;
             }
         }
     },"t2");
     t2.start();

     new Thread(()->{
         sleep(1);
         x = 10;
         t2.interrupt();
     },"t1").start();
     while(!t2.isInterrupted()) {
         Thread.yield();
     }
     System.out.println(x);
}
/*
运行结果:
10
*/

案例6

对变量默认值(0,false,null)的写,对其它线程对该变量的读可见

    static int a;
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(a);
        }).start();

    }
/*
运行结果:
0
*/

案例7

具有传递性,如果 x hb-> y 并且 y hb-> z 那么有 x hb-> z ,配合 volatile 的防指令重排,有下面的例子

volatile static int x;
static int y;
new Thread(()->{
 y = 10;
 x = 20;
},"t1").start();
new Thread(()->{
 // x=20 对 t2 可见, 同时 y=10 也对 t2 可见
 System.out.println(x);
},"t2").start();
/*
运行结果:
20
*/

以上就是java线程之Happens-before规则的详细内容,更多关于线程Happens-before规则的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java内存模型之happens-before概念详解

    简介 happens-before是JMM的核心概念.理解happens-before是了解JMM的关键. 1.设计意图 JMM的设计需要考虑两个方面,分别是程序员角度和编译器.处理器角度: 程序员角度,希望内存模型易于理解.易于编程.希望是一个强内存模型. 编译器和处理器角度,希望减少对它们的束缚,以至于编译器和处理器可以做更多的性能优化.希望是一个弱内存模型. ​因此JSR-133专家组设计JMM的核心目标就两个: 为程序员提供足够强的内存模型对编译器和处理器的限制尽可能少 ​下面通过一段代

  • volatile与happens-before的关系与内存一致性错误

    volatile变量 volatile是Java的关键词,我们可以用它来修饰变量或者方法. 为什么要使用volatile volatile的典型用法是,当多个线程共享变量,且我们要避免由于内存缓冲变量导致的内存一致性(Memory Consistency Errors)错误时. 考虑以下的生产者消费者例子,在一个时刻我们生产或消费一个单位. public class ProducerConsumer { private String value = ""; private boolea

  • Java内存模型(JMM)及happens-before原理

    我们知道java程序是运行在JVM中的,而JVM就是构建在内存上的虚拟机,那么内存模型JMM是做什么用的呢? 我们考虑一个简单的赋值问题: int a=100; JMM考虑的就是什么情况下读取变量a的线程可以看到值为100.看起来这是一个很简单的问题,赋值之后不就可以读到值了吗? 但是上面的只是我们源码的编写顺序,当把源码编译之后,在编译器中生成的指令的顺序跟源码的顺序并不是完全一致的.处理器可能采用乱序或者并行的方式来执行指令(在JVM中只要程序的最终执行结果和在严格串行环境中执行结果一致,这

  • 深入理解happens-before和as-if-serial语义

    概述 本文大部分整理自<Java并发编程的艺术>,温故而知新,加深对基础的理解程度. 指令序列的重排序 我们在编写代码的时候,通常自上而下编写,那么希望执行的顺序,理论上也是逐步串行执行,但是为了提高性能,编译器和处理器常常会对指令做重排序. 1) 编译器优化的重排序.编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序. 2) 指令级并行的重排序.现代处理器采用了指令级并行技术来将多条指令重叠执行.如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序. 3) 内存系统的

  • java线程之Happens before规则案例详解

    目录 正文 案例1 案例2 案例3 案例4 案例5 案例6 案例7 正文 happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见. 案例1 线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见 static int x; static Object m = new Object(); new T

  • Java struts2请求源码分析案例详解

    Struts2是Struts社区和WebWork社区的共同成果,我们甚至可以说,Struts2是WebWork的升级版,他采用的正是WebWork的核心,所以,Struts2并不是一个不成熟的产品,相反,构建在WebWork基础之上的Struts2是一个运行稳定.性能优异.设计成熟的WEB框架. 我这里的struts2源码是从官网下载的一个最新的struts-2.3.15.1-src.zip,将其解压即可.里面的目录页文件非常的多,我们只需要定位到struts-2.3.15.1\src\core

  • java设计模式责任链模式原理案例详解

    目录 引言 责任链模式定义 类图 角色 核心 示例代码 1.对请求处理者的抽象 2.对请求处理者的抽象 3.责任链的创建 责任链实现请假案例 案例类图 可扩展性 纯与不纯的责任链模式 纯的责任链模式 不纯的责任链模式 责任链模式主要优点 职责链模式的主要缺点 适用场景 模拟实现Tomcat中的过滤器机制 运行过程如下 分析Tomcat 过滤器中的责任链模式 引言 以请假流程为例,一般公司普通员工的请假流程简化如下: 普通员工发起一个请假申请,当请假天数小于3天时只需要得到主管批准即可:当请假天数

  • Java基础之枚举Enum类案例详解

    一.文章序言 Java中引用类型:数组.类.接口.枚举.注解 枚举这个既熟悉又陌生的东西具体再哪里可以使用呢? 什么是枚举? 枚举是一个引用类型,枚举就是一个规定了取值范围的变量类型. 枚举变量不能使用其他的数据,只能使用枚举中常量赋值.提高程序安全性: //格式: public enum 枚举名{ //枚举的取值范围 //枚举中可以生命方法 } 枚举的使用场景介绍? 1.最常见的情况如星期,相关变量我们会在Java里面重复使用,在这里我们就可以来定义一个叫做"星期"的枚举. publ

  • Java dom4j生成与解析XML案例详解

    一)dom4j介绍 使用方式:在pom.xml中导入dom4j对应的jar <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> 优点:dom4j使Java生成和解析XML灵活性变高,并且代码易于维护 API操作类: Document:表示xml文档信

  • Java web.xml之contextConfigLocation作用案例详解

    在web.xml中通过contextConfigLocation配置spring,contextConfigLocation参数定义了要装入的 Spring 配置文件. 部署applicationContext.xml文件         如果不写任何参数配置,默认的是在/WEB-INF/applicationContext.xml        如果指定了要加载的文件,则会去加载相应的xml,而不会去加载/WEB-INF/下的applicationContext.xml.如果没有指定的话,默认

  • Java Hibernate使用SessionFactory创建Session案例详解

        SessionFactory在Hibernate中实际上起到了一个缓冲区的作用 他缓冲了HIbernate自动生成SQL语句和其他的映射数据 还缓冲了一些将来有可能重复利用的数据     为了能创建一个SessionFactory对象 应该在Hibernate初始化的时候创建一个Configuration类的实例 并将已经写好的映射文件交给他处理 这样Configuration对象就可以创建一个SessionFactory对象 当SessionFactory对象创建成功后 Configu

  • Java for循环常见优化方法案例详解

    目录 方法一:最常规的不加思考的写法 方法二:数组长度提取出来 方法三:数组长度提取出来 方法四:采用倒序的写法 方法五:Iterator 遍历 方法六:jdk1.5后的写法 方法七:循环嵌套外小内大原则 方法八:循环嵌套提取不需要循环的逻辑 方法九:异常处理写在循环外面 前言 我们都经常使用一些循环耗时计算的操作,特别是for循环,它是一种重复计算的操作,如果处理不好,耗时就比较大,如果处理书写得当将大大提高效率,下面总结几条for循环的常见优化方式. 首先,我们初始化一个集合 list,如下

  • Java jpa外连接查询join案例详解

    1.IndexTagController.java @GetMapping("/tags/{id}") public String types(@PageableDefault(size = 3,sort = {"updateTime"},direction = Sort.Direction.DESC)Pageable pageable, @PathVariable long id, Model model, HttpSession session){ //找到所有

  • Java静态代理与动态代理案例详解

    代理模式 代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问. 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层. 代理模式的元素是:共同接口.代理对象.目标对象. 代理模式的行为:由代理对象执行目标对象的方法.由代理对象扩展目标对象的方法. 代理模式的

随机推荐