定义
单例模式(Singleton Pattern):确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
特点
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
几种实现方式
饿汉式
public class SingletonHungry {
private static SingletonHungry singletonHungry = new SingletonHungry();
private SingletonHungry() {
System.out.println("SingletonHungry is create");
}
public static SingletonHungry getInstance() {
return singletonHungry;
}
}
缺点:Singleton实例在什么时候被创建是不受控制的,对于静态成员singletonHungry,它会在类第一次初始化的时候被创建,如果该函数里面有一个静态成员变量,外部有方法引用了这个静态成员变量,该类就会被初始化,那么singletonHungry也会被创建。
解决办法如下:
只有在getInstance()方法被第一次调用的时候,SingletonHungry的实例才会被创建,这个方法巧妙地使用了内部类和类的初始化方法,内部类SingletonHolder被申明为private,使得我们不可能在外部访问并初始化他,只可能在getInstance()内部对SingletonHolder类进行初始化,利用虚拟机的类初始化机制创建单例。
public class SingletonHungry {
private SingletonHungry() {
System.out.println("SingletonHungry is create");
}
private static class SingletonHolder {
private static SingletonHungry instance = new SingletonHungry();
}
public static SingletonHungry getInstance() {
return SingletonHolder.instance;
}
}
懒汉式
线程不安全,也就是说第一个线程刚好执行到判断为null的时候,第二个线程也进来了,这样就造成了生成两个实例。
public class SingletonDemo {
private static SingletonDemo singletonDemo = null;
/**
* 这里首先要私有构造函数,不允许new实例,只提供一个公共的创建实例方法
*/
private SingletonDemo() {
}
/**
* 这里用到static是因为这个类构造函数私有化了,不能new实例出来,只有用类直接调用静态方法
* @return
* @throws SingletonException
*/
public static SingletonDemo getSingleton(){
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}
public void showSingleton() {
System.out.println("我是单例模式哦!");
}
}
懒汉式线程安全
直接在创建实例的方法上加synchronized ,这样虽然避免了线程不安全的问题,但是执行效率会很低。
public static synchronized SingletonDemo getSingleton(){
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}
懒汉式高效线程安全
当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
public class SingletonDemo {
private volatile static SingletonDemo singletonDemo = null;
private SingletonDemo() {
}
public static SingletonDemo getSingleton(){
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}
public void showSingleton() {
System.out.println("我是单例模式哦!");
}
}