引言:在网上经常听到一些牛人谈论设计模式的事,自己也只能是个看客,看看别人是如何犀利的。在好奇心的驱使下,我也打算学习学习设计模式,以后也好跟别人交谈。下面来看看最基础的设计模式---单例模式。
单例模式的要点有三个
1.某个类只能有一个实例
2.它必须自行创建这个实例
3.它必须自行向整个系统提供这个实例
从具体实现角度来说就是以下三点
1.单例模式的类只提供私有的构造函数
2.类定义中含有一个该类的静态私有对象
3.该类提供了一个静态的共有的函数用于创建或获取它本身的静态私有对象
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer
Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。
看了上面的这段描述,对单例模式的存在价值也知道了个大概。
在网上看到有很多种形式的单例模式,在此我们仅仅只看这三种常用形式:懒汉式单例、饿汉式单例、双重锁的式单例。
public class Singleton {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//懒汉式(在第一次调用的时候实例化)
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getSingleton(){
if(instance==null){
System.out.println("aaa");
instance=new Singleton();
}
return instance;
}
//饿汉式(在类初始化时,已经自行实例化)
/*private static Singleton instance=new Singleton();
private Singleton(){
}
public static Singleton getSingleton(){
System.out.println("bbb");
return instance;
}*/
//双重锁的形式
/*private static Singleton instance=null;
private Singleton(){
}
public static Singleton getSingleton(){
if(instance==null){
System.out.println("1");
synchronized(Singleton.class){
if(instance==null){
System.out.println("2");
instance=new Singleton();
}
}
}
return instance;
}*/
}
下面来写一个测试类,看看是不是只创建了一个实例
public class testSingleton {
public static void main(String[] args) {
Singleton instance1=Singleton.getSingleton();
instance1.setName("111");
System.out.println("instance1 name:"+instance1.getName());
Singleton instance2=Singleton.getSingleton();
instance2.setName("222");
System.out.println("instance2 name:"+instance2.getName());
System.out.println("instance name:"+Singleton.getSingleton().getName());
System.out.println(instance1==instance2);
}
}
打印结果如下:
aaa
instance1 name:111
instance2 name:222
instance name:222
true
由此可以看出,确实只创建了一个实例。
看到这里不知道大家有没有发现一个问题,懒汉式和饿汉式都存在线程安全的问题,如果你的进程中同时有多个线程去调这个类的方法,难道还是只会产生一个实例吗?下面我们来看看:
public class threadTest implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"====>"+Singleton.getSingleton());
}
}
public static void main(String[] args) {
threadTest t1 = new threadTest();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
打印结果如下:
aaa
A====>test.Singleton@ca0b6
A====>test.Singleton@ca0b6
A====>test.Singleton@ca0b6
A====>test.Singleton@ca0b6
A====>test.Singleton@ca0b6
aaa
B====>test.Singleton@10b30a7
B====>test.Singleton@10b30a7
B====>test.Singleton@10b30a7
B====>test.Singleton@10b30a7
B====>test.Singleton@10b30a7
由此可以看出,多个线程同时调用是实例就并非唯一了,所以就出现了线程不安全的问题了。如果想要它是线程安全的,那么就可以采用Singleton中双重锁的形式。
使用双重锁的形式后再来看看打印结果:
1
2
B====>test.Singleton@14318bb
B====>test.Singleton@14318bb
B====>test.Singleton@14318bb
B====>test.Singleton@14318bb
B====>test.Singleton@14318bb
A====>test.Singleton@14318bb
A====>test.Singleton@14318bb
A====>test.Singleton@14318bb
A====>test.Singleton@14318bb
A====>test.Singleton@14318bb
很显然实例就唯一了。初次接触,有错误的地方还望各位不惜指点,感激不尽!!!