细说java多线程之内存可见性

课程名称: 细说java多线程之内存可见性
课程地址:https://www.imooc.com/learn/352
课程评价:内容讲的一般吧,讲的知识体系不够完善,还有些讲错了。不怎么适合新手,老手也就图个检验所学知识。

第2章 2-1 可见性介绍

课程内容
什么是可见性
jmm内存模型
jmm内存模型
工作内存和主内存
线程数据读写规定
如何保证可见性?
可见性实现原理
可见性的实现方式
图片.png

第3章 synchronized实现可见性

synchronized实现可见性
synchronized为什么可以实现可见性?

sychronized实现可见性的过程

互斥

这个讲师讲解大致的流程没错,但是概念上有多个地方是不对的。工作内存中值的清除并没有进行清除操作,而是cpu只是简单标注为失效,并且这个失效标注的动作,是在解锁的时候发生的,加锁的时候如果发现这个值失效,会从主内存重新读一次,所以讲师要注意,不要误导广大网友。

三种重排序

重排序

as-if-serial

不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。

java内存中的变量都有指针引用,上下文引用成链,这个链是不会被打乱重排序的,只有没有数据依赖关系的代码,才会被冲排序,所以在单线程内部重排序不会改变程序运行结果,这就是as-if-serial

单线程遵守as-if-serial

多线程发生可见性问题

多线程发生可见性问题
图片.png

大大的疑惑?

2.1和2.2间没有数据依赖关系?(好像没有)所以因为没有数据依赖关系,所以真的会存在这种重排序吗?
这样cpu不得多执行计算出mid变量,有时还用不上这个mid变量。

可见性问题分析


可见性分析

volatile

volatile的特性

volatile的特性)

volatile实现可见性的原理

  • 这里提到插入一条sotre的屏障指令和一条load屏障指令,但是其实不够完善,volatile变量的读写前面也可能会加屏障指令。


    volatile的原理
源码分析不能保证原子性
原子性
volatile无法保证原子性
  void readAndWrite();
    descriptor: ()V
    flags:
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #4                  // Field a:I
         5: iconst_1            #iconst_1指令将number的值5压入栈后,cpu资源释放,此时即使number的值在工作内存失效,也不会导致 iadd重新从主内存获取6的值再进行 + 1 
         6: iadd
         7: putfield      #4                  // Field a:I
        10: return
      LineNumberTable:
        line 20: 0
        line 21: 10
}
SourceFile: "Test.java"

解决原子性问题方案

解决方案
适用场景
synchronized和volatile的比较

从内存可见性角度讲,volatile读相当于加锁(volatile读时,前面的操作加了内存屏障,且对该volatile共享变量的写操作,它对volatile读是可见的,所以这些操作都跟synchronized加锁一样),volatile写相当于解锁(volatile写时,也会加入内存屏障,防止后面的操作跟volatile进行重排序等,对volatile写时,会强制刷新到主内存中,这跟synchronized解锁一样,解锁前需要把共享变量刷新到主内存中去,确保了可见性)

课程总结

  • java语言层面有三种:synchronized,volatile,final
可见性
图片.png
double和long的读写非原子性

这是因为jvm的规范并没有要求64位的long或者double的写入是原子性的。在32位的机器上,一个64位变量的写入可能被拆分成两个32位的写操作来执行,这样如果只写入32位,而cpu释放,那么读取的线程就会只读到“”一半的值”。

volatile本身不保证获取和设置操作的原子性,仅仅保持修改的可见性。但是java的内存模型保证声明为volatile的long和double变量的get和set操作是原子的。转自慕课问答,楼下有疑惑的亲们看一下吧~~~

package mkw.demo.syn;

public class SynchronizedDemo {
    //共享变量
    private boolean ready = false;
    private int result = 0;
    private int number = 1;   
    //写操作
    public void write(){
        ready = true;                        //1.1              
        number = 2;                         //1.2               
    }
    //读操作
    public void read(){              
        if(ready){                           //2.1
            result = number*3;      //2.2
        }       
        System.out.println("result的值为:" + result);
    }

    //内部线程类
    private class ReadWriteThread extends Thread {
        //根据构造方法中传入的flag参数,确定线程执行读操作还是写操作
        private boolean flag;
        public ReadWriteThread(boolean flag){
            this.flag = flag;
        }
        @Override                                                                    
        public void run() {
            if(flag){
                //构造方法中传入true,执行写操作
                write();
            }else{
                //构造方法中传入false,执行读操作
                read();
            }
        }
    }

    public static void main(String[] args)  {
        SynchronizedDemo synDemo = new SynchronizedDemo();
        //启动线程执行写操作
        synDemo .new ReadWriteThread(true).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //启动线程执行读操作
        synDemo.new ReadWriteThread(false).start();
    }
}
package mkw.demo.vol;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class VolatileDemo {

    private Lock lock = new ReentrantLock();
    private int number = 0;
    
    public int getNumber(){
        return this.number;
    }
    
    public void increase(){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        lock.lock();
        try {
            this.number++;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final VolatileDemo volDemo = new VolatileDemo();
        for(int i = 0 ; i < 500 ; i++){
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    volDemo.increase();
                }
            }).start();
        }
        
        //如果还有子线程在运行,主线程就让出CPU资源,
        //直到所有的子线程都运行完了,主线程再继续往下执行
        while(Thread.activeCount() > 1){
            Thread.yield();
        }
        
        System.out.println("number : " + volDemo.getNumber());
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容