java中单根_Java 单根模式(Singleton Pattern) 学习

刚开始接触Singleton pattern,用以下代码实现:

Code 1

public class Config {

//Log4j instance

private static Logger logger = Logger.getLogger(Config.class);

// Class member, read config from properties file

private PropertiesConfiguration m_configProps;

// Initialize the single instance

private static Config m_instance = new Config();

// Config Factory, Return instance to consumer

public static Config getInstance() {

return m_instance;

}

... ...

}

马上就有人说lazy_load不错,使用lazy load,在类被使用的时候才初始化,于是改进了代码:

Code 2

public class Config {

private static Logger logger = Logger.getLogger(Config.class);

private PropertiesConfiguration m_configProps;

private static Config m_instance = new Config();

public static Config getInstance() {

if (m_instance == null) // step 1

// Create instance until the instance is used in the first time

m_instance = new Config(); //step 2

}

return m_instance;

}

有了这次改进,自我感觉良好,一直这么用了一段时间,来到多线程的世界,突然发现,咦,这个有多线程访问问题啊(额,太少接触多线程问题了)。问题描述:假设有两个线程1,2访问该类,按如下顺序访问Singleton

1. 线程1执行到step2是挂起,实例未创建,

2. 线程2这时执行到step1,符合判断条件,执行step2,创建一个实例

3. 线程1继续执行step2,又创建了一个实例,singleton失去意义

于是继续改进代码:

Code 3

public class Config {

private static Logger logger = Logger.getLogger(Config.class);

private PropertiesConfiguration m_configProps;

private static Config m_instance = new Config();

public static synchronized Config getInstance() {

if (m_instance == null) // step 1

// Create instance until the instance is used in the first time

m_instance = new Config(); //step 2

}

return m_instance;

}

恩,问题解决了,可是在thinking in java中说synchronized方法比普通方法调用消耗要多6倍,于是又想改进Code3,于是采用synchronized对象和double-check机制改进了代码,

Code 4

public class Config {

private static Logger logger = Logger.getLogger(Config.class);

private PropertiesConfiguration m_configProps;

private static Config m_instance = new Config();

public static synchronized Config getInstance() {

// to optimize synchoronized check

// until the instance is null, synchronize Config.class

if (m_instance == null) { //step 1

synchronized (Config.class) {

// If the instance is null, create a new one

if (m_instance == null)

m_instance = new Config(); //step 2

}

}

return m_instance;

}

恩,这次貌似非常不错了,很高兴,结果马上被人交了一盆冷水:Out-of-order writes, Java platform memory model问题,当然C++里面也有这个问题。简单点说就是new一个Config对象,本来执行顺序是:

1. 系统分配内存,创建对象

2. 初始化对象(constructor)

3. 把对象和引用关联起来

但是有可能出现的情况是

1.系统先创建对象

2. 把对象和引用关联起来

3. 初始化对象

这样可能导致m_instance引用不为空,但是指向的对象还没有初始化。考虑如下场景:假设两个线程1,2

1.线程1执行step1,判断引用为空,执行step2

2.线程1获得对象和引用的关联,但是对象还没有初始化

3.线程2抢占资源,开始执行step1,这个时候m_instance不为空,直接return m_instance

4.线程2获得一个没有初始化的对象,程序出错

这个时候考虑使用volatile关键字,很遗憾:According to the JLS (seeResources), variables declaredvolatile are supposed to be sequentially consistent, and therefore, not reordered. But two problems occur with trying to usevolatile to fix the problem with double-checked locking:

1. The problem here is not with sequential consistency. Code is being moved, not reordered.

2. Many JVMs do not implement volatile correctly regarding sequential consistency anyway.

搞来搞去,还是最原始的code1和不考虑性能的code3好,个人比较喜欢code1。

貌似java5的enum也可以用来搞singleton。。。

更新:

更多参考link:http://tomcat-oracle.iteye.com/blog/1993500

Updated:

Question: Why can’t we use a static class instead of singleton?

Answer:

One of the key advantages of singleton over static class is that it can implement interfaces and extend classes while the static class cannot (it can extend classes, but it does not inherit their instance members). If we consider a static class it can only be a nested static class as top level class cannot be a static class. Static means that it belongs to a class it is in and not to any instance. So it cannot be a top level class.

Another difference is that static class will have all its member as static only unlike Singleton.

Another advantage of Singleton is that it can be lazily loaded whereas static will be initialized whenever it is first loaded.

Singleton object stores in Heap but, static object stores in stack.

We can clone the object of Singleton but, we can not clone the static class object.

Singleton can use the Object Oriented feature of polymorphism but static class cannot.

Question: Can the singleton class be subclassed?

Answer: Frankly speaking singleton is just a design pattern and it can be subclassed. However it is worth to understand the logic or requirement behind subclassing a singleton class as the child class might not inherit the singleton pattern objective by extending the Singleton class. However the subclassing can be prevented by using the final keyword in the class declaration.

Question: Can there be multiple instance of singleton using cloning?

Answer: That was a good catch! What do we do now? To prevent the another instance to be created of the singleton instance we can throw exception from inside the clone() method.

Question: What is the impact if we are creating another instance of singleton using serialization and deserialization?

Answer: When we serialize a class and deserialize it then it creates another instance of the singleton class. Basically as many times as you deserialize the singleton instance it will create multiple instance. Well in this case the best way is to make the singleton as enum. In that way the underlying Java implementation takes care of all the details. If this is not possible then we will need to override thereadobject() method to return the same singleton instance.

Question: Which other pattern works with Singleton?

Answer:There are several other pattern like Factory method, builder and prototype pattern which uses Singleton pattern during the implementation.

Question: Which classes in JDK uses singleton pattern?

Answer: java.lang.Runtime : In every Java application there is only one Runtime instance that allows the application to interface with the environment it is running. The getRuntime is equivalent to the getInstance() method of the singleton class.

Uses of Singleton design pattern:

Various usages of Singleton Patterns:

Hardware interface access: The use of singleton depends on the requirements. However practically singleton can be used in case external hardware resource usage limitation required e.g. Hardware printers where the print spooler can be made a singleton to avoid multiple concurrent accesses and creating deadlock.

Logger : Similarly singleton is a good potential candidate for using in the log files generation. Imagine an application where the logging utility has to produce one log file based on the messages received from the users. If there is multiple client application using this logging utility class they might create multiple instances of this class and it can potentially cause issues during concurrent access to the same logger file. We can use the logger utility class as a singleton and provide a global point of reference.

Configuration File: This is another potential candidate for Singleton pattern because this has a performance benefit as it prevents multiple users to repeatedly access and read the configuration file or properties file. It creates a single instance of the configuration file which can be accessed by multiple calls concurrently as it will provide static config data loaded into in-memory objects. The application only reads from the configuration file at the first time and there after from second call onwards the client applications read the data from in-memory objects.

Cache: We can use the cache as a singleton object as it can have a global point of reference and for all future calls to the cache object the client application will use the in-memory object.

参考资料:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值