博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Item 3 - What is an efficient way to implement a singleton pattern in Java?
阅读量:5068 次
发布时间:2019-06-12

本文共 7382 字,大约阅读时间需要 24 分钟。

Depending on the usage, there are several "correct" answers.

Since java5 the best way to do it is to use an enum:

public enum Foo {   INSTANCE;}
The Right Way to Implement a Serializable Singletonpublic enum Elvis {    INSTANCE;    private final String[] favoriteSongs =        { "Hound Dog", "Heartbreak Hotel" };    public void printFavorites() {        System.out.println(Arrays.toString(favoriteSongs));    }}

理解:JDK5之后,建议用用枚举类的方式实现单例的方式。

Pre java5, the most simple case is:

public final class Foo {    private static final Foo INSTANCE = new Foo();  //加载Foo的时候对INSTANCE进行了实例化    private Foo() {        if (INSTANCE != null) {            throw new IllegalStateException("Already instantiated");        }    }    public static Foo getInstance() {        return INSTANCE;    }}
 

Let's go over the code. First, you want the class to be final. In this case, I've used the final keyword to let the users know it is final. Then you need to make the constructor private to prevent users to create their own Foo. Throwing an exception from the constructor prevents users to use reflection to create a second Foo. Then you create a private static final Foo field to hold the only instance, and a public static Foo getInstance() method to return it. The Java specification makes sure that the constructor is only called when the class is first used.

When you have a very large object or heavy construction code AND also have other accessible static methods or fields that might be used before an instance is needed, then and only then you need to use lazy initialization.

You can use a private static class to load the instance. The code would then look like:

public final class Foo {    private static class FooLoader {        private static final Foo INSTANCE = new Foo();    }    private Foo() {        if (FooLoader.INSTANCE != null) {            throw new IllegalStateException("Already instantiated");        }    }    public static Foo getInstance() {        return FooLoader.INSTANCE;             //调用getInstance()方法时对FooLoader类进行了加载并实例化了INSTANCE    }}

Since the line private static final Foo INSTANCE = new Foo(); is only executed when the class FooLoader is actually used, this takes care of the lazy instantiation, and is it guaranteed to be thread safe.

When you also want to be able to serialize your object you need to make sure that deserialization won't create a copy.

 
public final class Foo implements Serializable {    private static final long serialVersionUID = 1L;    private static class FooLoader {        private static final Foo INSTANCE = new Foo();    }    private Foo() {        if (FooLoader.INSTANCE != null) {            throw new IllegalStateException("Already instantiated");        }    }    public static Foo getInstance() {        return FooLoader.INSTANCE;    }    @SuppressWarnings("unused")    private Foo readResolve() {        return FooLoader.INSTANCE;    }}

The method readResolve() will make sure the only instance will be returned, even when the object was serialized in a previous run of your program.

 



 

While implementing Singleton we have 2 options

1. Lazy loading
2. Early loading

Lazy loading adds bit overhead(lots of to be honest) so use it only when you have a very large object or heavy construction code AND also have other accessible static methods or fields that might be used before an instance is needed, then and only then you need to use lazy initialization.Otherwise choosing early loading is a good choice.

Most simple way of implementing Singleton is

public class Foo {    // It will be our sole hero    private static final Foo INSTANCE = new Foo();    private Foo() {        if (INSTANCE != null) {            // SHOUT            throw new IllegalStateException("Already instantiated");        }    }    public static Foo getInstance() {        return INSTANCE;    }}

Everything is good except its early loaded singleton. Lets try lazy loaded singleton

 

class Foo {    // Our now_null_but_going_to_be sole hero     private static Foo INSTANCE = null;    private Foo() {        if (INSTANCE != null) {            // SHOUT              throw new IllegalStateException("Already instantiated");        }    }    public static Foo getInstance() {        // Creating only  when required.        if (INSTANCE == null) {            INSTANCE = new Foo();        }        return INSTANCE;    }}

So far so good but our hero will not survive while fighting alone with multiple evil threads who want many many instance of our hero. So lets protect it from evil multi threading

class Foo {    private static Foo INSTANCE = null;    // TODO Add private shouting constructor    public static Foo getInstance() {        // No more tension of threads        synchronized (Foo.class) {            if (INSTANCE == null) {                INSTANCE = new Foo();            }        }        return INSTANCE;    }}

but it is not enough to protect out hero, Really!!! This is the best we can/should do to help our hero

class Foo {    // Pay attention to volatile    private static volatile Foo INSTANCE = null;    // TODO Add private shouting constructor    public static Foo getInstance() {        if (INSTANCE == null) { // Check 1            synchronized (Foo.class) {                if (INSTANCE == null) { // Check 2                    INSTANCE = new Foo();                }            }        }        return INSTANCE;    }}

This is called "Double-Checked Locking idiom". It's easy to forget the volatile statement and difficult to understand why it is necessary.

For details : 

Now we are sure about evil thread but what about the cruel serialization? We have to make sure even while de-serialiaztion no new object is created

class Foo implements Serializable {    private static final long serialVersionUID = 1L;    private static volatile Foo INSTANCE = null;    // Rest of the things are same as above    // No more fear of serialization    @SuppressWarnings("unused")    private Foo readResolve() {        return INSTANCE;    }}

The method readResolve() will make sure the only instance will be returned, even when the object was serialized in a previous run of our program.

Finally we have added enough protection against threads and serialization but our code is looking bulky and ugly. Lets give our hero a make over

public final class Foo implements Serializable {    private static final long serialVersionUID = 1L;    // Wrapped in a inner static class so that loaded only when required    private static class FooLoader {        // And no more fear of threads        private static final Foo INSTANCE = new Foo();    }    // TODO add private shouting construcor    public static Foo getInstance() {        return FooLoader.INSTANCE;    }    // Damn you serialization    @SuppressWarnings("unused")    private Foo readResolve() {        return FooLoader.INSTANCE;    }}

 

Yes this is our very same hero :)

Since the line private static final Foo INSTANCE = new Foo(); is only executed when the class FooLoader is actually used, this takes care of the lazy instantiation,

and is it guaranteed to be thread safe.

And we have came so far, here is the best way to achieve everything we did is best possible way

public enum Foo {       INSTANCE;   }

Which internally will be treated like

public class Foo {    // It will be our sole hero    private static final Foo INSTANCE = new Foo();}

 

转载于:https://www.cnblogs.com/Guoyutian/p/5077524.html

你可能感兴趣的文章
输入月份和日期,得出是今年第几天
查看>>
pig自定义UDF
查看>>
spring security 11种过滤器介绍
查看>>
代码实现导航栏分割线
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
枚举的使用
查看>>
luogu4849 寻找宝藏 (cdq分治+dp)
查看>>
日志框架--(一)基础篇
查看>>
关于源程序到可运行程序的过程
查看>>
转载:mysql数据库密码忘记找回方法
查看>>
scratch少儿编程第一季——06、人在江湖混,没有背景怎么行。
查看>>
【贪心+DFS】D. Field expansion
查看>>
C# Async与Await的使用
查看>>
Mysql性能调优
查看>>
iOS基础-UIKit框架-多控制器管理-实例:qq界面框架
查看>>
自定义tabbar(纯代码)
查看>>
小程序底部导航栏
查看>>
poj1611 简单并查集
查看>>
Ubuntu 14.04下安装CUDA8.0
查看>>