• 【面试:并发篇30:多线程:happen-before】


    【面试:并发篇30:多线程:happen-before】

    00.前言

    如果有任何问题请指出,感谢。

    01.介绍

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

    02.happens-before规则

    规则一

    线程解锁 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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    规则二

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

    	volatile static int x;
    	new Thread(()->{
    	    x = 10;
    	},"t1").start();
    	
    	new Thread(()->{
    	    System.out.println(x);
    	},"t2").start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    规则三

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

    	static int x;
    	x = 10;
    	
    	new Thread(()->{
    	    System.out.println(x);
    	},"t2").start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    规则四

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

    	static int x;
    	Thread t1 = new Thread(()->{
    	    x = 10;
    	},"t1");
    	
    	t1.start();
    	t1.join();
    	System.out.println(x);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    规则五

    线程 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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    规则六

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

    规则七

    具有传递性,如果 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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    01.智慧商城——项目介绍与初始化
    查询性能提升3倍!Apache Hudi 查询优化了解下?
    .NET Framework 2023 年 8 月安全和质量汇总更新
    成为会带团队的技术人 在管理艺术中寻找确定性的“工程逻辑”
    Laravel Fillable() 使用
    分享一下微信公众号怎么实现积分商城功能
    node.js环境安装和VUE-cli脚手架搭建
    【27】c++设计模式——>迭代器模式(遍历双向链表)(2)
    【Datawhale】动手学数据分析
    web:[GXYCTF2019]Ping Ping Ping
  • 原文地址:https://blog.csdn.net/m0_71229547/article/details/126062060