高并发的可见性搞不明白,就不用再研发了

本篇重点介绍可见性是java中一种并不直观的特性 , 是指线程之间的可见性 , 即一个线程修改的状态对另一个线程是否是可见的 , 也就是一个线程修改了内存中的结果另一个线程能否马上就能看到 。 通常情况下 , 因为线程执行速度的快慢导致了线程间数据读取的先后问题 , 我们无法确保执行读操作的线程能适时地看到其他线程写入的值 , 有时甚至是根本不可能的事情 。 在高并发中可见性问题是保障线程之间交互的一个重要知识点 。
禁止缓存的可见性变量volatile是轻量级的同步机制
关键点:保证可见性、不保证原子性、禁止指令重排
保证可见性
解析:当多个线程访问同一个变量时 , 一个线程修改了这个变量的值 , 其他线程能够立即看到修改的值 。
当不添加volatile关键字时示例:
package com.jian8.juc;import java.util.concurrent.TimeUnit;/** * 1验证volatile的可见性 * 1.1 如果int num = 0 , number变量没有添加volatile关键字修饰 * 1.2 添加了volatile , 可以解决可见性 */public class VolatileDemo {public static void main(String[] args) {visibilityByVolatile();//验证volatile的可见性}/*** volatile可以保证可见性 , 及时通知其他线程 , 主物理内存的值已经被修改*/public static void visibilityByVolatile() {MyData myData = http://kandian.youth.cn/index/new MyData();//第一个线程new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t come in");try {//线程暂停3sTimeUnit.SECONDS.sleep(3);myData.addToSixty();System.out.println(Thread.currentThread().getName() + "\t update value:" + myData.num);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}, "thread1").start();//第二个线程是main线程while (myData.num == 0) {//如果myData的num一直为零 , main线程一直在这里循环}System.out.println(Thread.currentThread().getName() + "\t mission is over, num value is " + myData.num);}}class MyData {//int num = 0;volatile int num = 0;public void addToSixty() {this.num = 60;}}输出结果:
thread1come inthread1update value:60//线程进入死循环当我们加上volatile关键字后 , volatile int num = 0;输出结果为:
thread1come inthread1update value:60mainmission is over, num value is 60//程序没有死循环 , 结束执行不保证原子性
描述:原子性是指数据整体在当前的业务中不可分割、具有完整性 , 数据在业务流转过程中必须保证完整 , 要么同时成功要么同时失败 。
验证示例(变量添加volatile关键字 , 方法不添加synchronized):
package com.jian8.juc;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;/** * 1验证volatile的可见性 *1.1 如果int num = 0 , number变量没有添加volatile关键字修饰 * 1.2 添加了volatile , 可以解决可见性 * * 2.验证volatile不保证原子性 *2.1 原子性指的是什么 *不可分割、完整性 , 即某个线程正在做某个具体业务时 , 中间不可以被加塞或者被分割 , 需要整体完整 , 要么同时成功 , 要么同时失败 */public class VolatileDemo {public static void main(String[] args) {//visibilityByVolatile();//验证volatile的可见性atomicByVolatile();//验证volatile不保证原子性}/*** volatile可以保证可见性 , 及时通知其他线程 , 主物理内存的值已经被修改*/ //public static void visibilityByVolatile(){}/*** volatile不保证原子性* 以及使用Atomic保证原子性*/public static void atomicByVolatile(){MyData myData = http://kandian.youth.cn/index/new MyData();for(int i = 1; i <= 20; i++){new Thread(() ->{for(int j = 1; j <= 1000; j++){myData.addSelf();myData.atomicAddSelf();}},"Thread "+i).start();}//等待上面的线程都计算完成后 , 再用main线程取得最终结果值try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}while (Thread.activeCount()>2){Thread.yield();}System.out.println(Thread.currentThread().getName()+"\t finally num value is "+myData.num);System.out.println(Thread.currentThread().getName()+"\t finally atomicnum value is "+myData.atomicInteger);}}class MyData {//int num = 0;volatile int num = 0;public void addToSixty() {this.num = 60;}public void addSelf(){num++;}AtomicInteger atomicInteger = new AtomicInteger();public void atomicAddSelf(){atomicInteger.getAndIncrement();}}执行三次结果为:
//1.mainfinally num value is 19580 mainfinally atomicnum value is 20000//2.mainfinally num value is 19999mainfinally atomicnum value is 20000//3.mainfinally num value is 18375mainfinally atomicnum value is 20000//num并没有达到20000禁止指令重排
描述:在计算机CPU中代码逻辑均是以一组组的指令形式交付给CPU 。 有序性是指在计算机执行程序时 , 为了提高性能 , 编译器在代码达到某些条件时会对代码逻辑的指令排序 。