转载请注明出处:http://blog.csdn.net/myleike/article/details/50366705
看过关于单例模式的这么一个段子,大概是这样的:
俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Singleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)。好了,说正题。
**单例模式也就是确保一个类只有一个实例,并提供一个全局访问点。**
在许多设计中,一些对象其实我们只需要一个,比如说对话框、缓存等等。你可能会说:不是利用java全局的静态变量就可以做到吗?确实可以这样做,但是要将对象赋值给一个全局变量,那么必须在程序一开始就创建好对象,对吧?万一这个对象非常耗资源,但又长时间不会使用,不就成了一种浪费?这时单例模式就可以很好的解决这个问题。
**经典的单例模式**
/*-------------------Singleton.java---------------------*/
public class Singleton{
//利用静态变量来记录Singleton的唯一实例
private static Singleton singleton;
//将构造方法声明为私有的,防止其他类随意调用
private Singleton(){};
//用getInstance()方法来实例化对象,并返回这个实例
public static Singleton getInstance() {
//对象为空时才对他进行实例化
if(singleton==null) {
System.out.println("创建了新的对象");
singleton = new Singleton();
}
return singleton;
}
}
/*--------------------Main.java----------------------*/
public class Main {
public static void main(String[] args) {
Singleton.getInstance();
Singleton.getInstance();
Singleton.getInstance();
}
}
/*------------------执行结果-------------------------*/
创建了新的对象
我们看到不管调用了多少次getInstance()方法,singleton对象都只实例化了一次。那么在多线程中呢?我们修改一下Main.java
/*--------------------Main.java----------------------*/
public class Main {
public static void main(String[] args) {
new Thread(runnable).start();
new Thread(runnable).start();
}
private static Runnable runnable = new Runnable() {
public void run() {
Singleton.getInstance();
}
};
}
/*------------------执行结果-------------------------*/
创建了新的对象
创建了新的对象
在多线程中,singleton被创建了多次。那我们加上同步呢?
懒汉式
/*-------------------Singleton.java---------------------*/
public class Singleton{
.......
public static synchronized Singleton getInstance() {
......
return singleton;
}
}
/*------------------执行结果-------------------------*/
创建了新的对象
问题确实得到了解决,但同步又会降低性能,又是一个新的问题。但是如果个体getInstance()的性能对你的应用程序不是很关键,那就忘了这件事吧,什么也别做。但是你要知道,同步一个方法可能造成程序执行效率下降100倍。
采用急切实例化,保证任何线程在访问getInstance()时,对象已经创建。
俄汉式
/*-------------------Singleton.java---------------------*/
public class Singleton{
private static Singleton singleton = new Singleton();
private Singleton(){};
public static Singleton getInstance() {
return singleton;
}
}
/*------------------执行结果-------------------------*/
创建了新的对象
使用双重检测加锁减少getInstance()方法的同步。
/*-------------------Singleton.java---------------------*/
public class Singleton{
......
public static Singleton getInstance() {
if(singleton==null) {
synchronized(Singleton.class) {
//对象为空时才对他进行实例化
if(singleton==null) {
System.out.println("创建了新的对象");
singleton = new Singleton();
}
}
}
return singleton;
}
}
/*------------------执行结果-------------------------*/
创建了新的对象
在这里,我们首先检查对象是否创建,如果没有创建才同步,这样就保证了只同步了一次。
以上四种就是常见的单例模式实现方法。哪在什么时候使用它们呢?它们各自的优缺点是什么呢?
经典模式:
很明显,这时最简单的一种方法,也有吧一个致命的错误,就是在多线程的情况下会创建多次对象。如果我们在不考虑使用多线程,就可以用它;
懒汉式:
这种方式能够解决多线程的问题,但是同步方法降低了性能。如果不考虑性能问题,就可以用它;
俄汉式:
这种方式在类加载时就创建了对象,使类加载变慢,虽然不是不是标准的单例模式,但还是解决了多线程的问题;
双重检测加锁:
这种方式解决了多线程问题,同时也解决了性能问题,但实现起来比较复杂。另外,采用该方法还得确定使用的是java5以上版本。
转载请注明出处:http://blog.csdn.net/myleike/article/details/50366705