第一种:(懒汉式——线程非安全)
public class DBinfo {
private static DBinfo dbinfo;
private DBinfo(){
}
public static DBinfo getDBinfo(){
if(dbinfo == null){
fbinfo = new DBinfo();
}
return dbinfo;
}
}
注意:这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。
第二种:(懒汉式——线程安全)
public class DBinfo() {
private static DBinfo dbinfo;
private DBinfo(){
}
public static synchronized DBinfo get DBinfo(){
if(dbinfo == null){
fbinfo =new DBinfo();
}
return dbinfo;
}
}
注意:这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading
但是,效率很低,极少情况下不需要同步。
第三种:(饿汉式)
public class DBinfo {
private static DBinfodbinfo = new DBinfo();
private DBinfo (){
}
public static DBinfo getdbinfo() {
return dbinfo;
}
}
注意:这种方式基于classloder机制避免了多线程的同步问题,但是,dbinfo在类装载时就实例化
虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getdbinfo方法
但是也不能确定有其他的方式(或者其他的静态方法)导致类装载
这时候初始化dbinfo显然没有达到lazy loading的效果。
第四种:(饿汉式——变种)
public class DBinfo {
public static DBinfo dbinfo = new DBinfo();
public class Dbinfo{
public static Dbinfo getDbinfo(){
return DBinfo.dbinfo;
}
}
}
注意:之一种是线程安全的,同时有时在用到的时候才会创建(利用了java虚拟机的类加载的特性)
第五种:(静态内部类)
public class DBinfo {
private static class Dbinfo {
private static final DBinfo dbinfo = new DBinfo();
}
private DBinfo() {
}
public static final DBinfo getDbinfo() {
return Dbinfo.dbinfo;
}
}
注意:这种方式同样利用了类加载的特性来保证初始化dbinfo时只有一个线程,但是在这种方式中DBinfo类被装载了
而dbinfo不一定会被初始化。这是因为Dbinfo类没有主动使用的机制,所以只有当显示调用getDbinfo()方法时
才会显示装载Dbinfo类,从而实例化dbinfo。
第六种:(枚举)
public enum DBinfo{
DBINFO;
public void whateverMethod() {
}
}
注意:这种方式,不仅能够避免多线程同步问题,而且还能防止反序列化重新创建新的对象,但因为1.5版本后才加入enum,所以这种用法还不是很常见。
总结:我们可以观察一下一上提供的几种使用方式,并考虑一下他们的使用场景。
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗。如日志文件、应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池。
应用场景:
(1)windows的Task Manager ——任务管理器。
(2)windows的Recycle ——回收站。
(3)Web计数器 ——大数据应用。
(4)应用程序的日志应用 ——文件共享,一直保持打开状态。
(5)Web应用配置对象的读取 ——配置文件是共享资源
(6)数据库连接池 ——节省打开或关闭数据库连接所引起的效率损耗,引用单例模式维护可大大降低这种损耗
(7)多线程的线程池设计 ——采用单例模式,可以方便线程池对其中的线程进行控制。
(8)操作系统的文件系统 ——个操作系统只能有一个文件系统。
(9)HttpApplication ——这一点对于熟悉ASP.Net(IIS)的整个请求生命周期的同学应该知道HttpApplication
也是单例模式,所有的HttpModule都共享一个HttpApplication实例。