Volatile(关键字)
是一个轻量级的同步机制,一个比较low的Synchronized ;
保证了可见性,不保证原子性,禁止指令重排(保证有序性);
指令重排: 在数据依赖的情况下,源码的顺序和编译的顺序不一致;所以多个线程中使用的变量能否保证一致性是无法确定的。
所以需要使用关键字Volatile禁止指令重排,从而避免了多线程情况下程序出现乱序执行的现象,也就是避免出现无序性;
public class a{
int a =11; //1
int b =12; //2
a=a+5; //3
b=a*a; //4
//这里可以进行1324等排序; 但是4不能作为开始的数据; 因为没a的数据值的依赖;
}
Volatile 禁止指令重排:
执行写操作的时候,会发出一条store屏障指令;保证被Volatile修饰的变量不会被其他变量进行排序;
执行读操作的时候,会发出一条load屏障指令;禁止其他没有被修饰的读操作和Volatile修饰的变量进行排序;
如果让volatile保证原子性
- Synchronized 保证原子性; 2 . 通过使用JUC下面的 AtomicInteger 保证了原子性 底层CAS原理;
JVM运行的实体是线程,而每个线程创建时,JVM都会为其创建一个工作内存;
JMM内存模型就规定.所有的变量都要存储到主内存中去;
在代码验证前要先粗略的讲解JMM内存模型;
JMM本身是一种抽象的概念, 并不是真实存在; 是一种规范. 规定了程序中各个变量的访问方式; (包括实例字段, 静态字段. 和构成数对象的元素), 需要保证 原子性、可见性和有序性;
JMM的同步规定:
1.线程解锁前: 必须把共享变量的值刷新回主内存;(共享内存区域; 存储着所有的变量,所有的线程都可以访问)
2.线程加锁前; ; 必须读取主内存的最新值到自己的工作内存(每个线程私有的数据区域);
可见性
每个线程对数据的**读,写.,赋值,**都需要将变量 拷贝到自己的工作内存中去;然后进行修改操作;并将修改操作的值,写回到主内存中去; 但同时别的线程不知道改了, 所以要通知其他线程,已经有线程对主内存数据进行了修改操作,主内存的数据值,已经不是最新值; 这个就是JMM内存模型中的第一个特性可见性;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class A {
//修饰加volatile,让AAA线程修改值,同步可见到其他线程,使本来main线程中while循环判断条件number==0为true的判断变成false;
//不加的话,main 和 AAA线程之间互相不可见, main线程会一直处于运行状态;
volatile int number = 0;
public void add01() {
this.number = 30;
}
public void yuanzixing01() {
//这个number实现了Volatile;
this.number++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void yuanzixing02() {
//这个number实现了Volatile;
atomicInteger.getAndIncrement();
}
}
/**
* 1. 验证volatile的可见性;
* 1.1 如果int number =0; number 的变量前根本没有添加valotile关键字进行修饰. 所以不可见;
* <p>
* 2. 保证Volatile 不保证原性;
* 2.1 不可分割.原子性
*/
public class VolatileDemo01 {
public static void main(String[] args) {
//Volatile 可见性的操作;
//SeeOkByVolatile();
//验证不保证原子性的方法;
SeeByyuanzixing();
}
//验证不保证原子性的方法; 每次的值都不等于20000 因为线程之间的值都进行了覆盖;
private static void SeeByyuanzixing() {
A a = new A();
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
for (int i1 = 1; i1 <= 2000; i1++) {
a.yuanzixing01();
a.yuanzixing02(); //保证原子性;
}
}, "BBB").start();
}
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + ": finally number value " + a.number);
System.out.println(Thread.currentThread().getName() + ": finally AtomicInteger number value " + a.atomicInteger);
}
//Volatile 可以保证可见性,及时通知其他线程;
private static void SeeOkByVolatile() {
A a = new A(); //创建的资源类;
//实现多线程的方法; 创建线程一: AAA
new Thread(() -> {
System.out.println("AAA线程未修改" + Thread.currentThread().getName() + ": " + a.number);//获取线程的名字;
try {
//暂停一会线程;
TimeUnit.SECONDS.sleep(3);
//修改值;调用之间定义的方法; 将number的值修改为30;
a.add01();
System.out.println("AAA线程修改后获取" + Thread.currentThread().getName() + ": " + a.number);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "AAA").start();
//main线程处于循环状态; 直接到number不再等于零;
while (a.number == 0) {
}
System.out.println("运行完毕;");
}
}
看视频后自行理解,不足点有, 欢迎建议, 必定整改. 不喜勿喷~~