逐梦少年,看你能不能发现宝藏( 八 )


class MyData{//MyData.java==>MyData.class ==>JVM字节码volatile int number = 0;public void addT060() {this.number = 60;}//请注意,此时前面是加了volitile关键字修饰的public /*synchronized*/ voidaddPlusPlus() {number++;}AtomicInteger atomicInteger = new AtomicInteger(0);public void addAtomic() {atomicInteger.getAndDecrement();}}/**1.验证volatile的可见性* 1.1假如int number = 0;number变量之前根本没有添加volatile关键字修饰 。也就是没有可见性 。* 1.2添加了volatile可以解决可见性问题 。** 2.验证volative不保证原子性* 2.1原子性是什么意思?*不可分割,完整性,即某个线程做某个任务的时候,中间不可以被加塞或者分割,需要整体完整,要么同时成功,要么同时失败 。* 2.2volitile是否可以保证原子性操作?*number++在多线程下是非线程安全的,如何不加synchronized解决这个问题呢?* 2.3 why?* 2.4 如何解决原子性?**加sync**使用我们的juc的automicInterger* */public class VolatileDemo {public static void main(String[] args) throws InterruptedException {//main是一切方法的运势入口MyData myData = http://www.kingceram.com/post/new MyData();for (int i =0; i < 20; i++) {new Thread(()->{for (int i1 = 1; i1 <= 1000; i1++) {myData.addAtomic();}},String.valueOf(i)).start();}//需要等待上面20个线程券都计算完成后,再用main线程取得最终的结果值看是多少?//TimeUnit.SECONDS.sleep(5);//一个是main线程,一个是GC线程while (Thread.activeCount()>2) {Thread.yield();}System.out.println(Thread.currentThread().getName()+"\t finally number value:"+myData.atomicInteger);//seeOkVolatile();}//volatile可以保证可见性,及时通知其他线程,著物理内存的值已经被修改 。public static void seeOkVolatile() {MyData myData = http://www.kingceram.com/post/new MyData();new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t come in");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}myData.addT060();System.out.println(Thread.currentThread().getName()+"\t update number value"+myData.number);},"AAA").start();//第二个线程是我们的main线程while (myData.number ==0) {//mian线程一直再这里寻寻啊,直到number值不在等于0}System.out.println(Thread.currentThread().getName()+"\t mission is over");}}
计算机在执行程序时,为了提高性能,编译器和处理器的常常会对指令做重排序,一般分为以下3种:
? 原代码----》编译器优化的重排----------》指令并行的重排---------》内存系统的重排------------》最终执行的指令
单线程环境里面确保程序最终执行结果和代码顺序的执行结果一致 。
处理器在惊醒重排序时,必须要考虑指令之间的数据依赖性 。
多线程中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果是无法预测的 。
实现禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象 。
? 先了解一个概念,内存屏障( )又称内存栅栏,是一个CPU指令,他的作用有两个:一个是保证特定操作的执行顺序 。
? 二是保证某些变量的内存可见性(利用该特性实现的内存可见性) 。
由于编译器和处理器都能执行指令重排优化 。如果在指令间插入一条 则会告诉编译器和CPU,不管什么指令都不能和这条 指令重排序,也就是说通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化 。内存屏障另外一个作用是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读到这些数据的最新版本 。
工作内存与主内存同步延迟现象导致的可见性问题 。
可以使用或关键字解决,他们都可以使一个线程修改后的变量立即对其他线程可见 。
对于指令重排导致的可见性问题和有序性问题 。