单例模式中为什么要使用final和static?

众所周知,为了保证某个对象在各个场景中使用的唯一性,常用的一种设计模式就是单例模式。我们最熟悉的单例模式饿汉模式如下:

public class SingleInstance {
    private static final SingleInstance instance = new SingleInstance();

    private SingleInstance() {
    }

    public static SingleInstance getInstance() {
        return instance;
    }
}

它的优势在于,在高并发程序的任何请求中,我们都可以唯一的使用这个对象,而不会创建出新的对象来。其中在创建singleInstance这个对象的时候,分别使用了private,static,final这三个关键词。private的作用显而易见,保证了对象只在此类中能够使用,同时也封装了singleInstance类的构造方法,保证不会再其他地方创建出新的对象。那么static和final关键词再这里起了什么作用呢?下面一探究竟。

1. static

static是什么?

static是java中的一个关键字,有详细的static关键词的概念说明如下:

  • A static method belongs to the class rather than the object of a class.
  • A static method can be invoked without the need for creating an instance of a class.
  • A static method can access static data member and can change the value of it.

这样看可能不是特别直观,直接使用一个程序来说明:

public class ClassLazyInit {
    public static void main(String[] args) {
        
        System.out.println(Collection.class.hashCode());
        System.out.println(Collection.flag);
    }
    static class Collection{
        static boolean flag=true;
        static{
            System.out.println("Collection initializing...");
        }
    }
}
1808253012
Collection init...
true

Process finished with exit code 0

从运行结果可以看到,当执行类的hashCode()方法时候,Collection中的static块并没有被初始化,当主函数中调用了Collection中的某个静态变量,这时候这个类才被初始化。

static的特殊含义

static可以保证在一个线程未使用其他同步机制的情况下总是可以读到一个类的静态变量的初始值。
很好理解的是,static变量是随着类被初次访问而初始化的。在多线程的环境中,需要保证一个变量在线程中的可见性是需要对内存做一些操作指令的。可以简易来描述下这个过程,当两个线程A,B对一个共享变量进行操作的时候,首先是把内存中的数据加载进各自的处理器中,然后在放入各自的寄存器。当A中更新共享变量的时候,首先会被放入写缓存器中,然后再写入高速缓存中,最后一步是放进内存中,每个处理器都有各自的写缓存器和高速缓存。所以在一个时间点,线程B读取的共享变量值并不是A更新的那一个,很可能是一个旧值。在计算机系统设计中,为了保证变量的可见性,有一种协议叫做缓存一致性协议,它的大概作用就是说,不同的处理器可以读取对方高速缓存中的值。这时候我们要保证可见性只需要一步,就是当共享变量被更新的时候,原子性保证把值写入高速缓存中就可以了,volatile的实现方式也是基于这种思想。那么static变量所做的事情就是,在某个线程调用的时候,就写入内存中这个值,保证内存中必然有这个值的存在,这里注意:static并不能保证多线程之后操作的可见性。

2. final

Java final variable

If you make any variable as final, you cannot change the value of final variable(It will be constant).

我们都知道,final修饰的变量值不会改变。但是在多线程的环境中,它还会保证两点,1. 其他线程所看到的final字段必然是初始化完毕的。 2. final修饰的变量不会被程序重排序。

下面举例说明

public class HttpRequest{
    private String id;
    private final Request request;
    public HttpRequest(String id, String name, String age){
        this.id=id;
        this.request=new Reqeust(String name, String age);
    }
    static class Request{
        private String name;
        private String age;
        public Request(String name, String age){
            this.name=name;
            this.age=age;
        }
    }
}

之上是一段很简单的初始化程序,当我们调用它的时候,它的编译如下:

http=new HttpRequest("200","wang","22");
----------------------------------
obj=allocate(HttpRequest.class);
obj.id="200";
objRequest=allocate(Range.class);
objRequest.name="wang";
objRequest.age="22";
obj.request=objRequest;
http=obj;

可以保证的是,objRequest的任何赋值操作都在被它的父类引用之前。因为加了final关键字,所以可以严格的保证之上的顺序。

3. 总结

我们回顾下,static保证了变量的初始值,final保证了不被JIT编译器重排序。对于一个单例模式来说,它所在的类在被引用的时候,static会保证它被初始化完毕,且是所有线程所见的初始化,final保证了实例初始化过程的顺寻性。两者结合保证了这个实例创建的唯一性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容