首页 > 代码库 > 设计模式-单例模式

设计模式-单例模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例,为什么做这种设计,有些现实服务中设备只有一个,不可能让一个设备同时去做相同的服务给多人,就需要单例模式进行控制了。

通常来说单例模式分为懒汉式与饿汉式,其中又有许多细节划分,不过我觉得很多东西多余初学者来说没有意义,只是随着时间的增长慢慢理解。

单例模式都是跟工厂模式结合的,通常来说都是工厂方法模式

单利模式创建遵循以下概念:

1,构造方法私有化

2,提供一个公开的方法获取类的实例

懒汉与饿汉的区别:

懒汉在需要调用实例的时候才会第一次创建,饿汉则在类加载时创建自身的实例。

懒汉:

懒汉式-多线程可能会出现创建多个实例

单例类 -

//懒汉
public class Singleton {
    private static Singleton singleton;

    public static Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }


    public void print(){
        System.out.println(singleton.hashCode());
    }
}

测试一下 ,通过打印hashcode  可以查看实例在内存中是否为同一个引用

创建一个线程类

public class Thread extends java.lang.Thread {


    @Override
    public void run(){
        try {
            Singleton.getSingleton().print();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

来测试:

public class MainTest {

    public static void main(String[] args){
        Thread thread;//这是上面的线程类
        for (int num = 0; num<=100 ;num++) {
            thread= new Thread();
            thread.start();
        }

    }
}

控制台打印:

 控制台:

技术分享

可以看出,单利模式已经成功了,所有线程在内存中都是调用的同一个实例的引用,可能因为cpu速率太快,每个线程都完整的跑完了,可这不是我要的效果。我要测试的是在在多线程情况下,可能创建多个实例的情况;

Thread.sleep(1000L)会让当前线程休眠一秒,并且不释放锁。

修改单例类:

public class Singleton {
    private static Singleton singleton;

    public static Singleton getSingleton() throws InterruptedException {
        if (singleton == null) {
            Thread.sleep(1000L);//休眠不释放锁,让其他线程进入,因为方法不是同步的,没有阻塞,所以其他方法也可以进入
            singleton = new Singleton();
        }
        return singleton;
    }
    public void print(){
        System.out.println(singleton.hashCode());
    }
}

 测试:

技术分享

 

 已经不能实现单例的需求

 

有一个方法就是加同步,来支持多线程操作

//懒汉-同步
public class Singleton {
    private static Singleton singleton;
        //加同步
    public static synchronized Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }


    public void print(){
        System.out.println(singleton.hashCode());
    }
}

饿汉式:

饿汉现在有很多种写法,饿汉的实例是基于JVM在ClassLoader时创建的。ClassLoader在类加载时会验证静态代码块,基于此可以做实例化操作等

最简单的饿汉:

public class Singleton {  
    private static Singleton singleton= new Singleton();  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    return singleton;  
    }  
}  

 

 

不过现在最常用的写法

比较常用的写法0-双重校验写法:

//双重检验
public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {
    }

    //如果多线程情况下
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) { //多线程进入 线程1 进入此处 并有锁,此时未创建实例 另一个线程进入,无法获取锁,被阻塞
                if (singleton == null) {  //线程1 进入此处并创建实例
                    singleton = new Singleton();
                }
            }//线程1创建实例并释放锁  ,然后线程2进入synchronized同步快,发现已经创建了实例
        }
        return singleton;
    }
}

 

设计模式-单例模式