在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. Hibernate遇到oracle之主键生成策略

    一直用Hibernate+mysql,感觉Hibernate很好用,也出过什么大问题:这周,公司的产品要部署到Orecle,虽然产品号称支持Oracle但是我自己知道,这个产品压根儿就没在Oracle ...

  2. linux下获取硬盘、内存、U盘大小及使用大小

    /* * 获取硬盘大小;内存大小;usb大小 */ #ifndef SYSINFOGET_H #define SYSINFOGET_H #include <stdio.h> //磁盘信息 ...

  3. 301跳转:IIS服务器网站整站301永久重定向设置方法(阿里云)

    欢迎来到重庆SEO俱乐部:搜索引擎优化学习交流QQ群224306761. 承接:seo优化.网站建设.论坛搭建.博客制作.全网营销 博主可接:百度百家.今日头条.一点资讯等软文发布,有需要请联系PE! ...

  4. selenium grid的使用与配置

    一.selenium grid的组成与作用:由一个集线器hub和多个客户机node组成,如果你的程序需要在不用的浏览器,不同的操作系统上测试,而且比较多的case需要多线程远程执行,那么一个比较好的测 ...

  5. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

  6. wordpress建站过程5——footer.php

    footer中写的就只有网站地图,公司信息等等简单东西而已: <?php wp_footer(); ?> <div class="footer"> < ...

  7. IIS下访问网络驱动器(网络位置)

    System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo.FileName = "cmd.ex ...

  8. Linux关闭selinux

    最近在折腾Linux服务器,配置环境时,安装php的一个拓展,明明编译成功了,就是加载不进去,phpinfo不显示,查看错误日志是显示加载失败,没权限==,配置ftp程序也会有意想不到的问题,搞了好久 ...

  9. 京东的SSO

    京东的sso流程: 初始访问状态: cookies: http请求: 1.在首页点击登陆,跳转至passport.360buy.com,给予验证cookie alc(可以试试在提交登陆信息前删除该co ...

  10. WebStorm 10.0.3安装

    转:http://www.cr173.com/soft/130969.html WebStorm 10是一款强大的HTML5编辑工具,是 JetBrains 推出的一款商业的 JavaScript 开 ...