单例模式
单件模式能够保证某一类型对象在系统中的唯一性,即某类在系统中只有一个实例。
它的用途十分广泛,打个比方,我们开发了一个简单的留言板,用户的每一次留言都要将留言信息写入到数据库中,最直观的方法是没次写入都建立一个数据库的链接。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例
1.私有化构造函数,不让其他程序创建的对象初始化。(当构造函数私有后,我们不能在外部类中实例化这个类,也就是不能创建这个类的对象,只能在本类内部创建对象,然后对外提供返回对象的方法,此时提供的对象是唯一的。)(构造函数就是跟类名一样的函数)
2.在本类中new一个静态本类对象。
3.定义一个静态成员函数,它的功能是让其他程序可以通过这个函数获取到本类的对象
-
一种叫饿汉模式 也就是在类加载的时候就饿了,非要创建实例,
不考虑创建对象的内存开销 -
二种叫懒汉模式 也就是,类加载时绝对不会创建实例的,
只有在需要使用的时候才创建实例对象. -
总结一下就是
饿汉式:我很饿,我一上来就要new个对象!
懒汉式:我先不new对象,等我干活的时候,我再去new
懒汉模式
```java
// Version 1
public class Single1 {
private static Single1 instance;
public static Single1 getInstance() {
if (instance == null) {
instance = new Single1();
}
return instance;
}
}
// Version 1.1
// 构造器改为私有的,这样能够防止被外部的类调用
//每次获取instance之前先进行判断,如果instance为空就new一个出来,否则就直接返回已存在的instance
public class Single1 {
private static Single1 instance;
private Single1() {}
public static Single1 getInstance() {
if (instance == null) {
instance = new Single1();
}
return instance;
}
}
// Version 2
//synchronized关键字之后,getInstance方法就会锁上
//避免了Version1中,可能出现因为多线程导致多个实例
public class Single2 {
private static Single2 instance;
private Single2() {}
public static synchronized Single2 getInstance() {
if (instance == null) {
instance = new Single2();
}
return instance;
}
}
// Version 3
//双重检查
public class Single3 {
private static Single3 instance;
private Single3() {}
public static Single3 getInstance() {
if (instance == null) {
synchronized (Single3.class) {
if (instance == null) {
instance = new Single3();
}
}
}
return instance;
}
}
第一个if (instance == null),其实是为了解决Version2中的效率问题,只有instance为null的时候,才进入synchronized的代码段——大大减少了几率。
第二个if (instance == null),则是跟Version2一样,是为了防止可能出现多个实例的情况
// Version 4
//volatile关键字的一个作用是禁止指令重排,把instance声明为volatile之后,对它的写操作就会有一个内存屏障(什么是内存屏障?),这样,在它的赋值完成之前,就不用会调用读操作。
//注意:volatile阻止的不singleton = new Singleton()这句话内部[1-2-3]的指令重排,而是保证了在一个写操作([1-2-3])完成之前,不会调用读操作(if (instance == null))。
public class Single4 {
private static volatile Single4 instance;
private Single4() {}
public static Single4 getInstance() {
if (instance == null) {
synchronized (Single4.class) {
if (instance == null) {
instance = new Single4();
}
}
}
return instance;
}
}
饿汉式
//饿汉式实现
public class SingleB {
private static final SingleB INSTANCE = new SingleB();
private SingleB() {}
public static SingleB getInstance() {
return INSTANCE;
}
}
-
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
-
懒汉式是延时加载,他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。真正用到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象
饿汉式有两大缺点:
1.资源的占用:
饿汉模式 在类创建的就得new好它的静态成员对象 故占用空间
2.线程安全
其他
// Effective Java 第一版推荐写法
//静态内部类
public class Singleton {
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
// Effective Java 第二版推荐写法
//枚举类
//创建枚举实例的过程是线程安全的
//但是不能被继承
public enum SingleInstance {
INSTANCE;
public void fun1() {
// do something
}
}
// 使用
SingleInstance.INSTANCE.fun1();
工厂模式
1、创建一个接口:
2、创建实现接口的实体类。
3、创建一个工厂,生成基于给定信息的实体类的对象。
4、使用该工厂,通过传递类型信息来获取实体类的对象。