第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;
	}

}

原子变量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();
	}
	
	
}

猜你喜欢

转载自blog.csdn.net/m0_37294838/article/details/127683513
今日推荐