• 第2节 volatile 关键字内存可见性


    内存可见性

    1. 内存可见性(Memory Visibility)是指当某个线程正在使用对象状态 而另一个线程在同时修改该状态,需要确保当一个线程修改了对象 状态后,其他线程能够看到发生的状态变化。
    2. 可见性错误是指当读操作与写操作在不同的线程中执行时,我们无 法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。
    3. 我们可以通过同步来保证对象被安全地发布。除此之外我们也可以 使用一种更加轻量级的volatile 变量。

    volatile 关键字

    Java 提供了一种稍弱的同步机制,即volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将volatile 看做一个轻量级的锁,但是又与锁有些不同:
    ➢ 对于多线程,不是一种互斥关系
    ➢ 不能保证变量状态的“原子性操作

    /*
     * 一、volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。
     * 					  相较于 synchronized 是一种较为轻量级的同步策略。
     * 
     * 注意:
     * 1. volatile 不具备“互斥性”
     * 2. volatile 不能保证变量的“原子性”
     */
    public class TestVolatile {
    	
    	public static void main(String[] args) {
    		ThreadDemo td = new ThreadDemo();
    		new Thread(td).start();
    		
    		while(true){
    			if(td.isFlag()){
    				System.out.println("------------------");
    				break;
    			}
    		}
    		
    	}
    
    }
    
    class ThreadDemo implements Runnable {
    
    	private volatile boolean flag = false;
    
    	@Override
    	public void run() {
    		
    		try {
    			Thread.sleep(200);
    		} catch (InterruptedException e) {
    		}
    
    		flag = true;
    		
    		System.out.println("flag=" + isFlag());
    
    	}
    
    	public boolean isFlag() {
    		return flag;
    	}
    
    	public void setFlag(boolean flag) {
    		this.flag = flag;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    原子变量CAS算法

    CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器
    操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并
    发访问。

    1. CAS 是一种无锁的非阻塞算法的实现。
    2. CAS 包含了3 个操作数:
      ➢ 需要读写的内存值V ➢ 进行比较的值A ➢拟写入的新值B
    3. 当且仅当V 的值等于A 时,CAS 通过原子方式用新值B 来更新V 的 值,否则不会执行任何操作

    原子变量

    类的小工具包,支持在单个变量上解除锁的线程安全编程。事实上,此包中的类可
    将volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。
    ⚫ 类AtomicBoolean、AtomicInteger、AtomicLong 和AtomicReference 的实例各自提供对
    相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。
    ⚫ AtomicIntegerArray、AtomicLongArray 和AtomicReferenceArray 类进一步扩展了原子操
    作,对这些类型的数组提供了支持。这些类在为其数组元素提供 volatile 访问语义方
    面也引人注目,这对于普通数组来说是不受支持的。
    ⚫ 核心方法:boolean compareAndSet(expectedValue, updateValue)
    ⚫ java.util.concurrent.atomic 包下提供了一些原子操作的常用类:

    1. AtomicBoolean 、AtomicInteger 、AtomicLong 、 AtomicReference
    2. AtomicIntegerArray 、AtomicLongArray
    3. AtomicMarkableReference
    4. AtomicReferenceArray
    5. AtomicStampedReference
    import java.util.concurrent.atomic.AtomicInteger;
    
    /*
     * 一、i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
     * 		  int i = 10;
     * 		  i = i++; //10
     * 
     * 		  int temp = i;
     * 		  i = i + 1;
     * 		  i = temp;
     * 
     * 二、原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。
     * 		1. volatile 保证内存可见性
     * 		2. CAS(Compare-And-Swap) 算法保证数据变量的原子性
     * 			CAS 算法是硬件对于并发操作的支持
     * 			CAS 包含了三个操作数:
     * 			①内存值  V
     * 			②预估值  A
     * 			③更新值  B
     * 			当且仅当 V == A 时, V = B; 否则,不会执行任何操作。
     */
    public class TestAtomicDemo {
    
    	public static void main(String[] args) {
    		AtomicDemo ad = new AtomicDemo();
    		
    		for (int i = 0; i < 10; i++) {
    			new Thread(ad).start();
    		}
    	}
    	
    }
    
    class AtomicDemo implements Runnable{
    	
    //	private volatile int serialNumber = 0;
    	
    	private AtomicInteger serialNumber = new AtomicInteger(0);
    
    	@Override
    	public void run() {
    		
    		try {
    			Thread.sleep(200);
    		} catch (InterruptedException e) {
    		}
    		
    		System.out.println(getSerialNumber());
    	}
    	
    	public int getSerialNumber(){
    		return serialNumber.getAndIncrement();
    	}
    	
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 相关阅读:
    Elasticsearch 8.9 服务端接收创建索引和查询索引信息源码
    IBM Spectrum Symphony 获享高度可扩展、高吞吐量、低延迟的工作负载管理
    java计算机毕业设计农产品交易系统源码+系统+mysql数据库+lw文档+部署
    对于噪声数据理解以及Min-Max 规范化和 Score规范化(零-均值规范化)的实例【数据预处理】
    致敬最美抗击疫情的逆行者 DIV布局大学生抗疫感动专题网页设计作业模板 疫情感动人物静态HTML网页模板下载
    SpringBoot - Failed to determine a suitable driver class
    Spring配置文件的详细介绍
    第三届国际品质节,群硕企业与OI产品共同获奖
    Mybatis -- 读取 DATE 类型字段时可能遇到的问题(夏令时问题)
    机器视觉工程师如何快速停止内耗,与自己和解
  • 原文地址:https://blog.csdn.net/m0_37294838/article/details/127683513