单例模式
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例).
特点
优点:
(1) 由于单例模式在内存中只有一个实例,减少内存开支,特别是一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化,单例模式就非常明显了
(2) 由于单例模式只生成一个实例,所以,减少系统的性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
(3) 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
(4) 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。
缺点:
(1) 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
(2) 单例对象如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。
_UML图:
使用场景
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
注意事项: getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。
public class singleObject {
private static singleObject object = new singleObject();
private singleObject() {
}
public static singleObject getInstance() {
return object;
}
public void print() {
System.out.println("你好啊!");
}
}
class demo{
public static void main(String[] args) {
// singleObject ob=new singleObject();//会编译错误
singleObject ob=singleObject.getInstance();
ob.print();
}
}
单例模式的实现方式
1.懒汉模式,线程不安全
//懒加载 (懒加载其实就是延时加载,即当对象需要用到的时候再去加载),线程不安全
public class single1 { //懒汉模式 线程不安全
private static single1 object;
private single1(){};
public static single1 getInstance(){
if(object==null){
object=new single1();
}
return object;
}
}
2.懒汉模式 线程安全
这种方式具备很好的懒加载,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
//懒加载 线程安全
public class single2 {//懒汉模式 线程安全
private static single2 object;
private single2(){};
public static synchronized single2 getInstance(){
if(object==null){
object=new single2();
}
return object;
}
}
3.饿汉模式 线程安全
这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到懒加载.
//不懒加载
public class single3 { //饿汉模式 线程安全
private static single3 object=new single3();
private single3(){};
public static single3 getInstance(){
return object;
}
}
4.双重校验锁
这种方式采用双锁机制,安全且在多线程情况下能保持高性能
public class single4 {//双重校验锁
private static volatile single4 object;
private single4(){};
public static single4 getInstance(){
if (object==null){
synchronized (single4.class){
if (object==null){
object=new single4();
}
}
}
return object;
}
}