1 Volatile详解
代码语言:javascript复制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);
}
}
}