单例模式
1、单例模式:保证一个类只有一个实例,并提供一个访问它的全局方法。
基本使用:
public class SingleInstance { private static SingleInstance instance;//定义全局的本类实例。 /** * 私有化构造方法,防止外部通过new 来实例化对象 */ private SingleInstance() { } /** * * @return 返回本类的唯一实例 */ public static SingleInstance getInstance(){ if (instance==null) {//当实例不存在时,才实例化,否则就返回当前存在的实例 instance=new SingleInstance(); } return instance; } }
调用:
/** * * 客户端调用 */ public static void main(String[] args) { SingleInstance instance1 = SingleInstance.getInstance(); SingleInstance instance2 = SingleInstance.getInstance(); if (instance1 == instance2) { System.out.println("他们相等"); } else { System.out.println("他们不相等-------"); } }
输出结果:
这就是单例模式的简单使用。
2、单例模式中的线程安全
public class SingleInstance { private static SingleInstance instance;//定义全局的本类实例。 /** * 私有化构造方法,防止外部通过new 来实例化对象 */ private SingleInstance() { } /** * * @return 返回本类的唯一实例 */ public static SingleInstance getInstance(){ if (instance==null) {//当实例不存在时,才实例化,否则就返回当前存在的实例 instance=new SingleInstance(); } return instance; } } /** * * 客户端调用 */ public static void main(String[] args) { //开启十个线程创建实例 for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { SingleInstance instance1 = SingleInstance.getInstance(); System.out.println("当前线程---> " + Thread.currentThread() + " 当前对象的hashcode值---> " + instance1.hashCode()); } }).start(); } }
运行结果:
结论:当多个线程同时访问getInstance()方法时,可能会创建多个实例。违反了单例模式的定义。
解决方法:
(1)同步synchronized方法:
运行结果:
缺点:每次调用getInstance()都会需要调用synchronized,影响性能。
(2)用synchronized双重锁定法优化同步
运行结果:
3、单例模式 的类型(懒汉式与饿汉式)
上面的讲解是懒汉式单例模式(需要在第一次引用时才会去实例化自己)。
而饿汉式单例模式就是:利用静态初始化的方式,让本类被加载时就实例化自己。
代码如下:
public class SingleInstance { private final static SingleInstance instance = new SingleInstance();// 直接实例化自己。 /** * 私有化构造方法,防止外部通过new 来实例化对象 */ private SingleInstance() { } /** * @return 返回本类的唯一实例 */ public static SingleInstance getInstance() { return instance; } }
结论:因为饿汉式是通过静态初始化的方式,使得类一加载就实例化对象,提前占用系统资源,而饿汉式又会面临多线程访问的安全性问题,需要经过双重性锁定的方式才能保证安全,所以存在就是合理,具体使用哪一种就见仁见智了。