在java开发过程中,final是大家常用的关键字,无非就是用来修饰类,方法和变量,来表名类不能被继承,方法不会被覆盖,变量不能被改变,悄悄的说一句,private方法也隐式的final。通过一段时间的学习,我想和大家分享一下final的内存语义。

在java并发编程的艺术中第三章这样描述过final的内存语义:

  1. 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
  2. 初次读一个包含final域对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

在初次读这两句话时,我是一脸懵逼,这个final到底用来干啥的?多读了几遍突然意识到,final类型的变量可以保证在多线程发布某个对象时,这个对象的final域变量能够被正常的初始化(在写final变量后加了storestore屏障,在读final变量前加了loadload屏障),而普通类型的变量可能不会被正确的初始化,这样导致该对象在多个线程之间出现不一致的情况,这也就是我们所说的引用溢出。罪魁祸首是处理器重排序,因为处理器重排序不会影响单线程语义,但会破坏多线程语义,导致发布对象处在一个不一致的状态。

举一个引用溢出的例子,大家倒背如流的双重判定的单例模式:

public class Singleton {
    private static Singleton uniqueInstance;
    private final String name;
    private Singleton(String name){
        this.name = name;
    }
    public static Singleton getInstance(String name){
        if(uniqueInstance == null){
            synchronized (Singleton.class){
                if(uniqueInstance == null){
                    uniqueInstance = new Singleton(name);
                }
            }
        }
        return uniqueInstance;
    }
}

有什么问题吗?相信细心的同学会说uniqueInstance应该用volatile修饰,但是大家有没有发现,我的这个Singleton有点不一样呢,多了一个final类型成员变量name。那个这个final类型的变量究竟有啥作用呢?

首先我先说一下大家平时用volatile时,这个volatile有什么作用吧?

public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(uniqueInstance == null){
            synchronized (Singleton.class){
                if(uniqueInstance == null){
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

假设有A和B两个线程来调用Singleton.getInstance()方法,A先拿到锁,执行uniqueInstance=new Singleton()时,volatile可以阻止new Singeton()时重排序,那么B在得到对象时,是一个已经初始化ok的对象。假设上述没有volatile关键字,那么会出现uniqueInstance不为空,但对象还未初始化的情况,导致B线程得到的是一个未初始化的对象,造成不一致的情况。当然对于A线程来说,重排序并不影响uniqueInstance的使用。

那么为什么加了一个final类型的name就可以不需要用volatile呢?

我们可以回头看看final内存语义的第一条,uniqueInstance在被赋值前,保证final类型的变量会被正确初始化,显然B线程使用这个对象时,这个uniqueInstance会在一个一致的状态上,如果Singleton多了一个普通类型的变量,不加volatile会出现多线程问题。不加volatile仅仅适用于Singleton的所有成员变量是final类型的情况下,这样发布的对象会在各个线程间处在一个一致的状态。

当然,不加volatile这种写法是我自己凭空造出来的,只是结合final的语义来分析一下,如有错误,欢迎批评指正,大家共同前行。

说说final关键字(好像有干货)的更多相关文章

  1. 浅析Java中的final关键字(转载)

    自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...

  2. 浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  3. 浅析final 关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...

  4. [转载]浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  5. 转载:浅析Java中的final关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...

  6. java中的final关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...

  7. 浅析Java中的final关键字(转)

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...

  8. java基础4:深入理解final关键字

    本文主要介绍了final关键字的使用方法及原理 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech 文章首发于我的个人博客: https://h2pl. ...

  9. 浅析Java中的final关键字--转

    转载自:http://www.importnew.com/18586.html#comment-581628 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关 ...

随机推荐

  1. pgmpy包的安装,以及conda的安装

    pgmpy包的安装,以及conda的安装 pgmpy的官方网站是这样说明安装过程的: 链接:Installation 共有三个步骤,第一步是安装依赖包 首先它讲述了在linux下使用pip安装的方法: ...

  2. request相关研究

    一.什么是httpservletrequest 用来处理一个对Servlet的HTTP格式的请求信息. 二.httpservletrequest的作用是什么 优点: 公共接口类HttpServletR ...

  3. php浏览历史记录的方法

    本文实例讲述了php浏览历史记录的方法.分享给大家供大家参考.具体实现方法如下: /** * 商品历史浏览记录 * $data 商品记录信息 */private function _history($ ...

  4. YII2.0 数据库增删改查

    /*==================== dkhBaseModel 数据库增删改查方法 start ================================*/ //新增一条数据 publ ...

  5. 寒假学干货之------android开发环境

    1.下载安装jdk(http://www.oracle.com/technetwork/java/javase/downloads/index.html)装se版的就可以了,复制jdk目录路径,之后配 ...

  6. OVERLAPPED相关的socket函数介绍

    OVERLAPPED相关的socket函数介绍 上一篇文章介绍了<Windows核心编程>OVERLAPPED结构与内核对象IOCompletionPort相关概念,见http://www ...

  7. 一:python入门

    Python简介 这点就不做陈述了,相信各位朋友已经已经有了一定的了解. Python特色: 1:简单 第一次接触Python给我的感觉它的语法阅读就像是阅读一本英文书的目录一样,简单易懂,它的语法要 ...

  8. java note

    1.List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复.

  9. 安装CocoaPods流程及常见问题(Xcode->homebrew->RVM->Ruby->CocoaPods)

    一.HomeBrew 1.(转)HomeBrew的安装和简单使用 http://blog.csdn.net/maojudong/article/details/7918291 2.homebrew的简 ...

  10. 对jquery新增加的class绑定事件

    当页面加载时,就会注册所有的事件,后面通过jquery新增的内容(<div class="item"></div>),再对新增的添加事件$(".i ...