单例设计模式
1.什么是单例设计模式?
单例设计模式是设计模式中最常见的一种。设计模式
(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
2.在什么时候使用单例设计模式?
(1)在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
(2)可能会被频繁调用的工具类
3.为什么要使用单例设计模式?
单例设计模式为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
4.单例设计模式可以解决的问题有哪些呢?
(1)可以保证一个类在内存中的对象的唯一性,在一些常用的工具类、线程池、缓存,数据库,账户登录系统、配置文件等程序中可能只允许我们创建一个对象,这是可以用单例设计模式解决。
(2)创建多个对象可能会引起程序的错误时,可以使用单例设计模式来限制创建对象的个数。
(3)当该对象要被频繁使用时,对内存和效率又有要求时,单例设计模式可以节省重复创建对象带来的内存消耗,从而提高效率。
在对单例设计模式有了一定的了解之后,我们来说说单例设计模式的特点、如何使用单例设计模式和一些注意事项。
5.单例设计模式的特点?
(1)单例类只有一个实例。
(2)单例类必须在其自身进行实例化。
(3)单例类必须向外提供一个获取实例的接口。
6.如何创建单例设计模式?
可分为一下几步:
(1)构造方法私有化,用private使构造方法私有化,使外界无法创建实例。
(2)创建静态的本类对象。
(3)为外界提供获取实例化的接口。
7.接下来我们通过代码来了解一下两种单例设计模式?
饿汉式
class Singleton1{
//构造方法私有化
private Singleton1(){}
//创建静态的本类对象。
private static Singleton1 s=new Singleton1();
//为外界提供获取实例化的接口。
public static Singleton1 getInstance(){
return s;
}
public void print(){
System.out.println("饿汉式测试");
}
}
懒汉式
class Singleton2{
//构造方法私有化
private Singleton2(){}
private static Singleton2 s;
public static Singleton2 getInstance(){
//若对象还未创建,创建静态的本类对象。
if(s==null){
s=new Singleton2();//懒加载
}
//为外界提供获取实例化的接口。
return s;
}
public void print(){
System.out.println("懒汉式测试");
}
}
8.以上懒汉法存在线程安全问题。举个例子,在多线程中,有多个线程同时调用getInstance
接口来获取实例化,那么可能会出现这种情况。第一个线程判断完if(s==null)
还未来得及实例化本类对象。这时第二个线程也进入了判断语句if(s==null)
,此时s确实为null,所以第二个线程也实例化对象。这样就会实例化两个Singleton
对象。
9.那么我们该如何解决这个问题呢?
说白了我们只要实现线程的同步就可以了
线程同步有以下几种方法:
(1)使用同步代码块
(2)使用同步方法
(3)使用Lock(更灵活的代码控制,可以做出判断)
多线程共享数据,会有安全问题,使用同步可以解决安全问题,但同时也牺牲性能,所以同步的代码块要尽量保持简短,把不随数据变化的相关代码移除同步块
那么下面我们用同步方法来举个例子吧
class Singleton2{
private Singleton2(){}
private static Singleton2 s;
//同步方法(synchronized )
public static synchronized Singleton2 getInstance(){
if(s==null){
s=new Singleton2();
}
return s;
}
public void print(){
System.out.println("懒汉式测试");
}
}
但是我们会发现这种方法的同步代码较多,所以较牺牲性能,那有没有其他同步方法能够减少同步代码,从而提高性能呢?
所以下面我们介绍一下单例模式懒汉式双重校验锁
public class Singleton {
/**
* 懒汉式变种,属于懒汉式中最好的写法,保证了:延迟加载和线程安全
*/
private static Singleton instance=null;
private Singleton() {};
public static Singleton getInstance(){
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
这种方法线程安全并且效率较高,是比较推荐使用的。