Java设计模式之Singleton单例模式篇
java 单例模式的实现方式 public class Singleton { private static Singleton instance; private Singleton (){ //首先有一个私有的构造器 } public static Singleton getInstance() { } 这种方式是线程不安全的,如果多个线程同时访问的话就可能有多个对象产生,如果在get方法中加同步块的话会影响性能。
public class Singleton { } 这种方式虽然不存在安全性问题,但是在程序启动的时候就会初始化。 实现3: public class Singleton { private static class SingletonHolder { public static Singleton getInstance() { } 3种方式中这是最好的解决方案,既解决了线程同步的问题,有在调用的时候才初始化。 单例模式主要有3个特点,: 1、单例类确保自己只有一个实例。 2、单例类必须自己创建自己的实例。 3、单例类必须为其他对象提供唯一的实例。 什么时候使用单例模式? 单例模式也是一种比较常见的设计模式,它到底能带给我们什么好处呢?其实无非是三个方面的作用: 第一、控制资源的使用,通过线程同步来控制资源的并发访问; 第二、控制实例产生的数量,达到节约资源的目的。 第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。 比 如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源。软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损 耗,这种效率上的损耗还是非常昂贵的。当然,使用数据库连接池还有很多其它的好处,可以屏蔽不同数据数据库之间的差异,实现系统对数据库的低度耦合,也可 以被多个系统同时使用,具有高可复用性,还能方便对数据库连接的管理等等。数据库连接池属于重量级资源,一个应用中只需要保留一份即可,既节省了资源又方 便管理。所以数据库连接池采用单例模式进行设计会是一个非常好的选择。 在我们日常使用的在Windows中也有不少单例模式设计的组件,象常用的文件管理器。由于Windows操作系统是一个典型的多进程多线程系统,那么在创建或者删除某个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象。采用单例模式设计的文件管理器就可以完美的解决这个问题,所有的文件操作都必须通过唯一的实例进行,这样就不会产生混乱的现象。 再比如,每台计算机可以有若干个打印机,如果每一个进程或者线程都独立地使用打印机资源的话,那么我们打印出来的结果就有可能既包含这个打印任务的一部分,又包含另外一个打印任务的一部分。所以,大多数的操作系统最终为打印任务设计了一个单例模式的假脱机服务Printer Spooler,所有的打印任务都需要通过假脱机服务进行。 实际上,配置信息类、管理类、控制类、门面类、代理类通常被设计为单例类。像Java的Struts、Spring框架,.Net的Spring.Net框架,以及Php的Zend框架都大量使用了单例模式。
|
第二个例子JAVA
java设计模式学习1--Singleton Pattern
前些天摆弄java,参考一些资料写了个数据库连接池,对里面只产生一个实例的那种做法深表佩服,今天中午又听到别人在说设计模式,受不了了,就上网Down了点资料来。
一来就看到了Singleton模式,一看,呀,不就是那个连接池里用的方法么?!噢,原来如此。
Singleton 是一种创建性模型,它用来确保只产生一个实例,并提供一个访问它的全局访问点。
为了实现 Singleton 模式,我们需要一个静态的变量,能够在不创建对象的情况下记忆是否已经产生过实例了。静态变量或静态方法都可以在不产生具体实例的情况下直接调用,这样的变量或方法不会因为类的实例化而有所改变。
实现 Singleton 模式的办法通常有三种:
1.用静态方法实现 Singleton;
2.以静态变量为标志实现 Singleton;
3.用注册器机制来创建 Singleton。
对于上面3种方法,我觉得第一种很好用,写的连接池用了第一种和第三种方法。用第一种方法使得怎么取都是那一个连接池,用第三种方法使得只存在那一个连接池。
第一种方法具体实现为:
声明构造函数为 private,防止通过除由我们提供的方法之外的任意方式来创建一个实例,如果不把构造函数声明为private,编译器就会自作聪明的自动同步一个默认的friendly构造器。下面是摘抄的一个例子:
public class Singleton
{
private static Singleton s;
private Singleton()
{
};
public static Singleton getInstance()
{
if (s == null)
s = new Singleton();
return s;
}
}
// 测试类
class singletonTest
{
public static void main(String[] args)
{
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
if (s1==s2)
System.out.println
("s1 is the same instance with s2");
else
System.out.println
("s1 is not the same instance with s2");
}
}
singletonTest运行结果是:
s1 is the same instance with s2
这证明我们只创建了一个实例,再怎么取都是那个实例,很简单也很实用。
对于第二种实现方法,在类中加入一个静态变量做为标志,每次都在构造函数里进行检察。
下面是我写的一个例子:
public class Singleton {
static boolean existInstance=false;
public Singleton()
{
if (existInstance)
{
System.out.println("Already exist instanse!");
}
else
{
//...........................
System.out.println("Create an instanse!");
existInstance=true;
}
}
}
测试类如下:
public class Test {
public static void main(String[] args) {
Singleton s1=new Singleton();
Singleton s2=new Singleton();
}
}
结果为:
Create an instanse!
Already exist instanse!
第二次的时候检测到已经有实例,接下来要怎么做就看自己的了。
与第一种方法相比,第一种是随便你怎么弄,都是那个实例,第二种是只能在第一次生成一个实例,再往后就会报错了。
下面来看看第三种方法:用注册器机制来创建 Singleton。
这种方法首先要建立一个管理器,用集合中的Hashtable 和Enumeration来实现addItem(Object key, Object value),getItem(Object key),removeItem(Object key)等方法实现,将key和value一一关联起来,创建实例前首先用addItem方法进行注册,再用getItem方法获取实例。
Hashtable中的key是唯一的,从而保证创建的实例是唯一的,用注册器机制来创建 Singleton模式的好处是易于管理,可以同时控制多个不同类型的Singleton 实例。
现在,我把那个连接池的部分代码弄出来讲讲第三种方法:
首先,定义个静态的hashtable:
public static Hashtable pools=new Hashtable();
当创建连接池成功的时候,把产生的连接池对象放入pools中:
DBConnectionPool pool=new DBConnectionPool(poolName, url, usr, pwd, max);(DBConnectionPool 是自定义的连接池对象)
pools.put(poolName, pool);
取连接的时候,用的是:
public Connection getConnection(String poolName)
{
DBConnectionPool pool=(DBConnectionPool)pools.get(poolName);
if(pool!=null)
{
return pool.getConnection();
}
return null;
}
前面说了,hashtable中的key值是唯一的,这样,名字为poolName的连接池只能有一个。
讲完了,收摊了,还看不懂我也没话说了.......