单例模式的意义:
有一些对象我们只需要一个实例,比如说线程池、缓存、对话框、日志对象、重放打印机、显卡等设备的驱动程序。这些对象只能有一个实例,否则会产生很多问题。
为了确保只有一个实例,有时我们通过全局变量的形式实现,但是将对象赋值给全局变量,但是却没有使用就会造成资源的浪费。所以还只实例化一个实例更好。
总所周知,类对象的构造函默认是public类型的,这样我就是说这个对象可以有很多实例。当然我们构造函数虽然不是公有的类型(如protected),只有同一个包的类可以实例化它时,但是仍可以实例化多次,
私有的构造函数不能被类外实例化,只能类内部实例化。但很显然不能够通过类的实例来调用构造器,因为类实例的产生和构造器的调用就像"鸡生蛋,蛋生鸡"一样, 谁先谁后说不清楚。但是如果通过类用却是可以的。可以通过调用该类的静态方法,再通过静态方法调用私有的构造函数。
单例模式确保一个类只有一个实例,并提供一个全局的访问点。
一个简单的单例模式的实现如下:
public class LazySingleton {
//利用一个静态变量记录LazySingleton的唯一实例
private static LazySingleton uniqueInstance;
//把构造器声明为私有的,只有自LazySingleton类内才可以调用构造器
private LazySingleton(){}
//用getinstance方法实例化对象,并返回这个实例。
public static LazySingleton singletonGetInstance() {
if(uniqueInstance != null){
//需要的时候就产生实例
uniqueInstance = new LazySingleton();
}else{
System.out.println("already exists lazySingleton instance");
}
return uniqueInstance;
}
}
通过懒汉模式获取单例在多线程的情况是不安全的,我们可以通过对获取实例的方式进行加锁。
public static synchronizedLazySingleton singletonGetInstance() {
if(uniqueInstance != null){
//需要的时候就产生实例
uniqueInstance = new LazySingleton();
}else{
System.out.println("already exists lazySingleton instance");
}
return uniqueInstance;
}
尽管如此,这种方式只有第一次执行的时侯,才真正需要同步。一旦设置好uniqueInstance这个变量,就不再需要同步这个方法了以后的每次调用都会显得累赘。
当然如果getInstanced()的性能对应用程序不是很关键,可以什么都不做。但是要考虑加了同步的方法性能可能下降100倍那么getInstance的方法被频繁使用,可能需要慎重考虑了。
当然我们可以把同步的地方换到方法内部,如下所示:
public class UpdatedLazySingleton {
//volatile关键词确保,当uniqueInstance变量被初始化成实例时,多个线程正确地处理uniqueInstance变量
private volatile static UpdatedLazySingleton uniqueInstance;
private UpdatedLazySingleton(){}
public static UpdatedLazySingleton getInstance() {
//检查实例,如果不存在则进入同步区块
if(uniqueInstance == null){
//只有第一次才彻底执行这里的代码
synchronized (UpdatedLazySingleton.class) {
if(uniqueInstance == null){
//进入区块后,再检查一次,如果仍是null,才创建实例
uniqueInstance = new UpdatedLazySingleton();
}
}
}
return uniqueInstance;
}
}
这种双重检查加锁的实现方式可以大大减少getInstance()的时间消耗。
如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,可能需要急切创建此单件:
public class HungrySingleton {
private static HungrySingleton uniqueInstance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return uniqueInstance;
}
}
这种做法依赖JVM在加载这个类时马上创建此唯一的单件实例。JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。