java设计模式之单例模式
2015-12-02 19:02
453 查看
在java中,单例模式(Singleton)保证了在一个jvm中只有一个实例存在。
为什么使用单例模式?
1.对于一些需要频繁创建的大型对象,可以减小开销。
2.减少new的操作,减少了内存的访问频率。
3.有些逻辑需值需要一个实例存在。
一个简单的单例模式
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
public static Singleton getInstance()
{
if(singletonInstance == null)
singletonInstance = new Singleton();
return singletonInstance;
}
}
分析:
该单例在多线程环境下是会出问题的。
改进一:在getInstance方法上加synchronized关键字
public static synchronized Singleton getInstance()
{
if(singletonInstance == null)
singletonInstance = new Singleton();
return singletonInstance;
}
分析:
这样在每次获取实例的时候都需要加锁,性能明显下降,实际上只需要在第一次创建实例的时候需要加锁,之后再获取实例就不需要再加锁了。
改进二:只在创建实例的时候加锁
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
public static Singleton getInstance()
{
if(singletonInstance == null){
synchronized(singletonInstance){
if(singletonInstance == null){
singletonInstance = new Singleton();
}
}
}
return singletonInstance;
}
}
分析:
这样还是会出现问题,主要是由于singletonInstance = new Singleton();这句话在jvm中执行的顺序造成的,如果jvm首先分配空间,然后赋给singletonInstance,最后初始化实例, 就会出现问题,如A、B两个线程,A、B同时进入if语句,A判断singletonInstance为空,执行new操作,jvm分配了一块空间并赋给singletonInstance,但并没有初始化,然后A离开synchronized块,B进入发现singletonInstance不为空,直接返回,但实际上此时并未初始化,在使用的时候就会出现问题。
改进三:使用内部类
public class Singleton {
private Singleton(){
}
private static class SingletonFactory
{
private static Singleton singletonInstance = new Singleton();
}
public Singleton getInstance()
{
return SingletonFactory.singletonInstance;
}
}
分析:
JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。实际上如果实例化抛出异常的话也会出问题。
另一种相对完美的实现:创建和获取实例分离
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
private static synchronized void init()
{
singletonInstance= new Singleton();
}
public static Singleton getInstance()
{
if(singletonInstance == null){
init();
}
return singletonInstance;
}
}
总结:实际上没有完美的方式,只不过根据自己的情况选择合适的方式罢了。
为什么使用单例模式?
1.对于一些需要频繁创建的大型对象,可以减小开销。
2.减少new的操作,减少了内存的访问频率。
3.有些逻辑需值需要一个实例存在。
一个简单的单例模式
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
public static Singleton getInstance()
{
if(singletonInstance == null)
singletonInstance = new Singleton();
return singletonInstance;
}
}
分析:
该单例在多线程环境下是会出问题的。
改进一:在getInstance方法上加synchronized关键字
public static synchronized Singleton getInstance()
{
if(singletonInstance == null)
singletonInstance = new Singleton();
return singletonInstance;
}
分析:
这样在每次获取实例的时候都需要加锁,性能明显下降,实际上只需要在第一次创建实例的时候需要加锁,之后再获取实例就不需要再加锁了。
改进二:只在创建实例的时候加锁
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
public static Singleton getInstance()
{
if(singletonInstance == null){
synchronized(singletonInstance){
if(singletonInstance == null){
singletonInstance = new Singleton();
}
}
}
return singletonInstance;
}
}
分析:
这样还是会出现问题,主要是由于singletonInstance = new Singleton();这句话在jvm中执行的顺序造成的,如果jvm首先分配空间,然后赋给singletonInstance,最后初始化实例, 就会出现问题,如A、B两个线程,A、B同时进入if语句,A判断singletonInstance为空,执行new操作,jvm分配了一块空间并赋给singletonInstance,但并没有初始化,然后A离开synchronized块,B进入发现singletonInstance不为空,直接返回,但实际上此时并未初始化,在使用的时候就会出现问题。
改进三:使用内部类
public class Singleton {
private Singleton(){
}
private static class SingletonFactory
{
private static Singleton singletonInstance = new Singleton();
}
public Singleton getInstance()
{
return SingletonFactory.singletonInstance;
}
}
分析:
JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。实际上如果实例化抛出异常的话也会出问题。
另一种相对完美的实现:创建和获取实例分离
public class Singleton {
private static Singleton singletonInstance = null;
private Singleton(){
}
private static synchronized void init()
{
singletonInstance= new Singleton();
}
public static Singleton getInstance()
{
if(singletonInstance == null){
init();
}
return singletonInstance;
}
}
总结:实际上没有完美的方式,只不过根据自己的情况选择合适的方式罢了。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统