关于Java中的单例模式

--------------------------- 题记

查了很多资料,然后汇总总结了一篇单例模式的文章。


--------------------------- 查询的相关博客资料

单例模式-内部类:

http://blog.sina.com.cn/s/blog_6d2890600101gb8x.html

http://blog.sina.com.cn/s/blog_765e27790101ab8x.html

http://blog.csdn.net/shutear/article/details/8038847

 

Synchronized

http://zhangjunhd.blog.51cto.com/113473/70300

http://hi.baidu.com/jiangyangw3r/item/a3d53ed6bb72b21e20e2504c

 

单例模式:

http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html

http://blog.sina.com.cn/s/blog_75247c770100yxpb.html

http://blog.csdn.net/wutianyin222/article/details/7911829



--------------------------- 单例模式

有些时候,允许自由创建某个类的实例没有意义,还可能造成系统性能下降(因为创建对象锁带来的系统开销问题)。


使用单例模式的三个条件

 使用private修饰该类的构造方法。

 提供一个public static的公共静态方法作为该类的访问点。

 必须缓存已创建的对象,使用private static私有静态成员变量类缓存。


使用代理模式的两个优势

 减少创建Java实例所带来的系统开销。

 便于系统跟踪单个Java实例的生命周期、实例状态等。


单例一:预加载

优点:线程安全,线程同时访问无性能下降问题。

缺点:加载类就创建对象,如果长期不使用,就导致资源浪费。

package test;

public class Singleton {
	//静态缓存点
	private static Singleton singleton = new Singleton();
	
	//私有构造方法
	private Singleton() {}
	
	//静态访问点
	public static Singleton getInstance() {

		return singleton;
	}
	
}

单例二:延迟加载(同步方法锁

优点:延迟加载,按需分配内存,线程安全(懒汉模式)。

缺点:多线程访问时,性能降低。

package test;

public class Singleton {
	//静态缓存点
	private static Singleton singleton;
	
	//私有构造方法
	private Singleton() {}
	
	//静态访问点
	public synchronized static Singleton getInstance() {//给方法上锁,不同线程不能同时进入该方法
		if (singleton == null) singleton = new Singleton();
		
		return singleton;
	}
	
}

注:对static方法使用synchronized时,加锁的对象为SingletonDemo.class,这个是线程安全的。如果对于成员方法(没有static修饰),加锁的对象为SingletonDemo.this,如果其他线程该类的其他对象访问该方法,synchronized对它是无效的,因为是对象锁,锁的是本对象其他线程对于该方法的访问。


单例三:延迟加载(双重检查锁

优点:延迟加载,按需分配内存,线程安全(懒汉模式)。

缺点:第一次线程同时访问时性能下降。

package test;

public class Singleton {
	//静态缓存点
	private static Singleton singleton;
	
	//私有构造方法
	private Singleton() {}
	
	//静态访问点
	public static Singleton getInstance() {
		if (singleton == null)
			synchronized (Singleton.class) {//给该类上锁,不同线程不能同时进入该类同步块
				if (singleton == null) singleton = new Singleton();
			}
		
		return singleton;
	}
	
}

注:如代码所示,此代码如果有成员变量需要对外访问,那么需要加入volatile关键字修饰对应的对象。若没有该关键字,则获取到的该成员变量不准确,该单例是个不健康的单例模式。若使用该关键字,则性能会降低,少了JVM的代码优化功能(具体看博客分析)。


单例四:延迟加载(内部类

package test;

public class Singleton {
	private static class SingletonHolder {
		//静态缓存点
		private static Singleton singleton = new Singleton();
	}
	
	//私有构造方法
	private Singleton() {}
	
	//静态访问点
	public static Singleton getInstance() {
		
		return SingletonHolder.singleton;
	}

}

注:因为java机制规定,内部类SingletonHolder只有在getInstance方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的(JVM实现线程安全)。内部类加载的时候实例化一次singleton


单例模式举例

 Servlet工作流程图如下:

 

 

那么在整个过程中,首先是容器接受请求,再把所有请求发送给dispatch中转站,中转站解析请求之后,根据请求的信息来调用不同的servlet,在调用servlet的时候使用多线程来代替多进程,从而提高性能。

在这过程中,有两个地方是单例,第一个是Dispatch类是个单例模式,第二个是Servlet容器,是个容器类型的单例。


 Servlet中的单例:

 Dispatch:标准的单例模式。

 Servlet容器:使用Map<String, Object>缓存的单例模式。


单例模式与工厂模式的结合举例

package test;

public class Singleton {
	//静态缓存点
	private static Singleton singleton;
	
	//私有构造方法
	private Singleton() {}
	
	//静态访问点(工厂)
	public static Singleton factory(String className) {
		if (singleton == null)
			synchronized (Singleton.class) {
				try {
					if (singleton == null) 
						singleton = (Singleton) Class.forName(className).newInstance();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		
		return singleton;
	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值