java 内存模型

java 内存模型

       概念

              定义了线程在访问内存时候会发生什么

 

重排序

       概念

              编译器和java虚拟机为了让程序运行的更有效率改变了原有代码的执行顺序

              这个执行顺序的改变就是重排序

       引发的问题

              一般情况下重排序没什么影响

                     仿佛对程序员并没有感知到重排序一样

              而在多线程程序中这种自动的重排序可能造成运行错误

              举例

                     思路

                            创建两个线程分别调用数据类的两个方法

                            这两个方法其中一个方法中代码满足重排序的可能

                            这种重排序会影响另一个方法的逻辑正确性

                     核心代码

                            public class test{

                                private int i = 0;

                                private int j = 0;

                           

                                public void setData(){

                                    i = 100;

                                    j = 50;

                                }

                           

                                public void show(){

                                    if(i < j){

                                        System.out.println("i < j");

                                    }

                                }

                            }

                     测试类

                            public class Main {

                                public static void main(String[] args){

                                    final test t = new test();

                                    new Thread(){

                                        public void run(){

                                            t.setData();

                                        }

                                    }.start();

                                    new Thread(){

                                        public void run(){

                                            t.show();

                                        }

                                    }.start();

                                }

                            }

                     输出

                            (几次都是空白)

                     说明

                            ……

                            说明按照图解java多线程中的例子不管用嘛…

                            P448

                     原理

                            由于i = 100 和 j = 50之间的顺序不存在任何逻辑依赖性

                            所以可能被重排序 进而 变成 j = 50 在 i = 100之前

                            又由于 两个线程并发,那么在j = 50 之后可能 另一个线程上了cup

                            然后执行了i < j 的判断,此时 i = 0 , j = 50 显然成立,然后打印

                            然而这样是和原来顺序的直观逻辑不一致的

                            这就是重排序带来影响

                     解决

                            这种设计的错误称为为正确同步

                                   一般都能通过synchronized和volatile解决

                            本例只要在两个方法上加上synchronized即可

 

可见性

       概念

              可见就是可读

              A线程对i字段写了一个值

              B线程可以读到这个i字段的值

              那么线程A对i的写值对B就是可见的

                     按书里的定义这个可见就是写值可见

                     其他线程读到的是写了之后的值

                     而不是写的过程中的值

       问题

              对多线程可能造成以为可读但事实上短暂不可读情况出现

       举例

              思路

                     线程类中run方法根据一个默认为真的条件设置一个死循环

                     再设置一个set方法让这个条件为假

                     目的是通过调用set方法让自动调用的run脱离死循环进行下面的操作

                     然而set方法的线程和run方法的线程不是同一个

                     条件的赋值有可能不可见,那么run方法可能永远都在死循环了

              核心代码

                     public class test extends Thread{

                         private boolean flag = false;

                         public void run(){

                             while(!flag){}

                             System.out.println("脱离死循环了!");

                         }

                         public void set(){

                             flag = true;

                         }

                     }

              测试类

                     public class Main {

                         public static void main(String[] args){

                             test t = new test();

                             t.start();

                             t.set();

                         }

                     }

              输出

                     脱离死循环了!

              说明

                     java多线程设计模式,这本书有毒…

              解决

                     书里说的是把flag设置成 volatile即可…

 

volatile

       被volatile修饰的字段具备可见性

              volatile保持可见性有性能代价

       volatile不具备互斥性,也就是线程遇到volatile不会去请求锁

       java api中没有long和double的原子操作类

              但是volatile可以作用在long和double上

 

共享内存与缓存的读写与可见性

       共享内存

              实例对象数据都在共享内存中

              由多个线程共享

       缓存

              局部变量都在栈中

              由各个线程独占

              局部变量的读写首先会访问各个线程独立的缓存

              各个线程的缓存之间是不可见的

                     想要变得可见就的利用共享内存

                     具备可见性的字段写值到缓存后会强制写到共享内存中

                     然后读的线程会强制让自己的缓存失效直接把共享内存的值写到局部缓存中

                     然后读的是可见的正确的值

 

synchronized的同步性和互斥性

       互斥性

              也就是锁的互斥

              只允许一个线程能拿到锁

              多个想拿到锁的线程是互斥的

              对锁是独占的

       同步性

              同步就是多个线程并发的时候数据的完整性是一致的同步的

              一个线程更新了值另一个线程读到的值也是更新的

              这个更新对所有并发的线程是同步的

                     原理

                            也就是互斥实现的

                            互斥保证了一个线程操作的完整性

                            操作完整当然也就能读到正确的值了

      

              由于同步性与互斥性

              又可以说synchronized能保证线程间不受重排序和可见性的影响

                           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值