Volatile详解

1 Volatile详解

package com.shi.jvm;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class MyData{
	
	volatile int num = 0;
	
	public void addTo60() {
		this.num = 60;
	}
	
	//目前num 是怎加了 volatile 修饰的 :验证不保证原子性
	public void addPlus() {
		num++;
	}
	
	/**
	 * 使用原子整形来保证原子性
	 */
	AtomicInteger atomicInteger = new AtomicInteger();
	public void myAddAtomic() {
		atomicInteger.getAndIncrement();
	}
	
}

/**
 * 1 验证volatile的可见性 : 就是及时通知别的线程该值发生变化了
 * 		1.1. 假如 int num = 0; 没有增加 volatile关键字的修饰
 * 		结果:主线程一直在循环,一直没有收到 num 改变的通知
 *  	1.2. 在  int num = 0 前面增加 volatile关键字
 *  	结果: 在线程1把 num值改变之后 立即收到通知,退出循环
 *  
 * 2 验证volatile 不保证原子性
 * 	 2.1 原子性什么意思?
 * 		不可分割,完整性,也即某个线程正在做具体业务时,中间不可以被加塞或者被分割,
 * 	   	需要整体完整,要么同时成功,要么同时失败
 * 	 2.2 volatile 不保证原子性 验证
 *   	启动20个线程,每个线程自加1000次 看最钟结果
 *   	结果:每次执行的 myData.num 结果都是不一样的 
 *   2.3 为什么?
 *   	原因:num++ 底层是要经过3步操作才完成的
 *   2.4 怎么解决
 *   	(1).在方法中增加 synchronized
 *   	(2).使用 AtomicInteger 来实现原子性
 * @author shiye
 *
 */
public class ValatileTest {

	public static void main(String[] args) {
		ValatileTest.notAtomic();
	}
	
	/**
	 * 1 验证方法的可见性
	 */
	public static void checkSee() {
		MyData myData = new MyData();
		
		//1 启动 1 个新的线程,在这个线程里面改变主线程里面的值
		new Thread( () -> {
			System.out.println(Thread.currentThread().getName() + "\t come in");
			//睡眠3秒
			try {
				TimeUnit.SECONDS.sleep(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			myData.addTo60();
			System.out.println(Thread.currentThread().getName() + "\t updated num value:" + myData.num);
		},"AAA").start();
		
		//2 主线程是第2个线程,一直在循环
		while(myData.num == 0 ) {
		}
		
		System.out.println(Thread.currentThread().getName() + "\t mission is over" + myData.num);
	}
	
	
	/**
	 * 2 volatile 验证不是原子性
	 */
	public static void notAtomic(){
		MyData myData = new MyData();
		for (int i = 0; i < 20; i++) {
			//启动20个线程,每个线程自家1000次
			new Thread(() -> {
				for (int j = 0; j < 1000; j++) {
					myData.addPlus();//没有实现原子性
					myData.myAddAtomic();//使用原子整形的方式来实现原子性
				}
			},String.valueOf(i)).start();
		}
		//需要等待上面20个线程全部执行完毕,再看main方法取得最终结果是多少
		while(Thread.activeCount()>2) {
			//剩下俩个线程一个是GC 另一个是main
			Thread.yield();
		}
		System.out.println(Thread.currentThread().getName() + "\t int mission is over : " + myData.num);
		System.out.println(Thread.currentThread().getName() + "\t AtomicInteger mission is over : " + myData.atomicInteger);
	}

}


/**
 * 在多级环境中无法保证指令执行的顺序是按照代码写的顺序执行的,有很多不可测性
 * @author shiye
 *
 */
class ReSortSeqDemo{
	int a = 0;
	boolean flag = false;
	
	public void method01() {
		a = 1;  //语句1
		flag = true; //语句2
	}
	public void method02() {
		if(flag) {
			a = a +5;
			System.out.println("method02 方法提前了 请注意a : " + a);
		}
	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券