介绍:
概念:
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)
正文:
单例模式没有什么可说的,大家多多少少都了解过一点,最有名的是"饿汉式”,“懒汉式”。单例的实现重要的一点是构造方法私有化,然后只返回一个对象,我们先写一个"饿汉式"。
public class Singleton {
//静态是因为实例还没初始化出来,所以可以通过类名来调用,下面的静态方法一个道理
//final修饰保证不可变唯一
//为什么叫饿汉,因为它很饿,JVM在加载这个类的时候,它就迫不及待的去创建唯一的单件实例
//保证任何线程访问之前先创建出来(很重要)。
private static final Singleton uniqueInstance = new Singleton();
private Singleton() {
}
public static Singleton getInstance(){
return uniqueInstance;
}
}
缺点也很明显,我如果不用这个实例,你的资源不就浪费了。
我们改进一下,当你用的时候,再加载不就完事了,这就是延迟加载也就是经常说的"懒汉式"。
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance(){
//判断一下,如果还没有实例,我在实例化,我很懒
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
那个资源浪费的问题看起来解决了,我们没有浪费资源,然而并没有,"懒汉式"在多线程环境下,有大问题。
我们弄两个线跑一下看有什么问题,我在创建对象后输出一下地址。
public static Singleton getInstance(){
if(uniqueInstance == null){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
uniqueInstance = new Singleton();
System.out.println(uniqueInstance);
}
return uniqueInstance;
}
//启动两个线程
public class MyThread{
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton instance = Singleton.getInstance();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Singleton instance = Singleton.getInstance();
}
}).start();
}
}
输出:
com.singleton.Singleton@4be63fd3
com.singleton.Singleton@3943de20
完犊子,输出两个地址,这明显不是单例了,我用一个图解释一下这个情况。
解决方法很简单,在getInstance加上synchronized,有人会说效率问题,现在synchronized效率已经很高了,我觉得可以忽略。
关键字的位子我觉得可以换换,我们只需保证有线程安全问题的地方不会出问题。这就是最后一种DCL双重锁机制。
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance(){
// 第一次检查instance是否被实例化出来,如果没有进入if块
if(uniqueInstance == null){
synchronized (Singleton.class){
// 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}