单例模式简介
Java中很多设计模式。今天我们就来讲第一种常用的模式——单例设计模式。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。在服务器和浏览器端,我们也会使用单利设计模式来解决客户访问的问题。另外,单例是单例,但是,这一个单例可以被多访问的。这就涉及到了线程安全的问题。
单例设计模式的总方式是:
1. 把构造函数私有化
2. 本类中创建一个静态私有的本类的对象(也可以先是引用,之后才创建)
3. 提供一个公共静态的方法返回创建好的本类对象
下面就来介绍单例设计模式的两种方式:懒汉式和饿汉式。
懒汉式:
public class SingleText {
//饿汉式
private static SingleText s =null;
private SingleText(){
System.out.println("单例被创建了");
}
public static SingleText returnSingle(){
if (s==null) {//这里一定要加判断,不然单例模式没有用。
s = new SingleText();
}
return s;
}
public void sup() {
System.out.println("mmmm");
}
public static void main(String[] args) {
SingleText s =SingleText.returnSingle();
s.sup();
SingleText s2 = SingleText.returnSingle();
s2.sup();
System.out.println(s==s2);
}
}
上面的代码运行的结果:
单例被创建了
mmmm
mmmm
true
从第四行和第三行就知道,这个类只创建了一个对象。
但是懒汉式的方式存在线程安全的问题。
所以我们要加一个双重判断及同步代码块的机制:这种方式很常用。
public static SingleText returnSingle(){
if (s==null) {
synchronized(SingleText.class){
if (s==null) {
s = new SingleText();
}
}
}
return s;
}
以上面的方式既可以保证线程安全,又能增加效率。
但是下面的方式比上面的方式更提高效率
使用静态内部类来创建单例的实例,在静态内部类创建实例,比上面双重判断加锁定效率更高。
这种方式利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。
public class SingleText {
//懒汉式,调用返回实例时才创建对象。
private static class InnerLoad{
private static SingleText s = new SingleText();
}
public static SingleText returnSingle(){
return InnerLoad.s;
}
public void sup() {
System.out.println("mmmm");
}
public static void main(String[] args) {
SingleText s1 = SingleText.returnSingle();
s1.sup();
SingleText s2 =SingleText.returnSingle();
s2.sup();
System.out.println(s1==s2);
}
}
通过下面运行结果,我们也能推断出,这种方式也实现了单例模式。
mmmm
mmmm
true
懒汉式:
public class SingleText {
//饿汉式,加载类时就已经实例化对象了
private static SingleText s = new SingleText();
private SingleText(){
}
public static SingleText returnSingle(){
return s;
}
public void cry() {
System.out.println("哇哇~~~~");
}
public static void main(String[] args) {
SingleText s1 = SingleText.returnSingle();
s1.cry();
SingleText s2 = SingleText.returnSingle();
s2.cry();
System.out.println(s1==s2);
}
}<strong>
</strong>
下面是运行结果:
哇哇~~~~
哇哇~~~~
true
恶汉式的单例设计模式是原本就具有线程安全性质的。所以不用考虑安全问题。