定义
保证一个类只有一个实例,并且提供一个访问该全局访问点
优缺点
优点:
- 一个类只有一个实例:防止其他对象对自己的实例化,确保所有的对象都访问一个实例。
- 有一定的伸缩性:类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩。
- 提供了对唯一实例的受控访问。
- 因为在系统内存种只存在一个对象,因此可以节约资源。
- 允许可变数目的实例。
- 避免对共享资源的多重占用。
缺点
- 不适用于变化的对象
- 单例模式没有抽象层,所以单例类的扩展有很大的困难。
- 单例类职责过重,在一定程度上违背了单一职责原则。
- 滥用单例会造成一些负面影响:为了节省资源将数据库连接池对象设计为的单例类,可能会导致,共享连接池对象的程序过多而出现连接池溢出。
- 如果实例化的对象长时间不被利用,系统会认为是 垃圾而被回收,这将导致对象状态的丢失。
应用
windows的任务管理器、回收站
任务管理器它不能打开两个
线程池:需要方便对池种的线程进行控制。
对于一些应用程序的日志应用,或者web开发中读取配置文件都适合使用单例模式,如HttpApplication 就是单例的典型应用。
网站计数器:如果你存在多个计数器,每一个用户的访问都刷新计数器的值,这样的话你的实计数的值是难以同步的
设计思想:
- 不允许其他程序用new对象(new就是开辟新的空间,每一次new都产生一个对象)
- 在该类中创建对象(这里的对象需要在本类中new出来)
- 对外提供一个可以让其他程序获取该对象的方法(因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象)
思想实现
(1)私有化该类的构造函数
(2)通过new在本类中创建一个本类对象
(3)定义一个公有的方法,将在该类中所创建的对象返回
饿汉式:类初始化,就会加载对象
public class Singleton {
//通过new在本类中创建一个本类对象
private static Singleton instance=new Singleton();
//构造方法私有
private Singleton(){
};
//定义一个公有的方法,将在该类中所创建的对象返回
public static Singleton getInstance(){
return instance;
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
优
- 在类加载的时候就完成了实例化,避免了线程的同步问题
缺
- 由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到这个实例,但是它也会加载,会造成内存的浪费(但是这个浪费可以忽略,所以这种方式也是推荐使用的)
懒汉式:调用getInstance方法的时候才会创建对象
这种方式是在调用getInstance方法的时候才创建对象的,所以它比较懒因此被称为懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {
};
public synchronized static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
如果不加synchronized锁:
此方式存在线程安全问题:
多个线程执行这个方法的时候会实例化多个对象
当第一个线程在执行if(instance==null)这个语句时,此时instance是为null的进入语句。
在还没有执行instance=new Singleton()时(此时instance是为null的)
第二个线程也进入if(instance==null)这个语句,
因为之前进入这个语句的线程中还没有执行instance=new Singleton(),
所以它会执行instance=new Singleton()来实例化Singleton对象,
因为第二个线程也进入了if语句所以它也会实例化Singleton对象。
这样就导致了实例化了两个Singleton对象。
所以单例模式的懒汉式是存在线程安全问题的
静态内部类[推荐用]
public class Singleton{
private Singleton() {
};
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
这里结合了懒汉式和饿汉式的优点,真正需要对象的时候才会加载,并且加载类线程是安全的。
⑤枚举[极推荐使用]
public class Singleton {
public static Singleton getInstance(){
return SingletonEnum.instance.getInstance();
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
private static enum SingletonEnum {
instance;
private Singleton singleton;
private SingletonEnum(){
singleton = new Singleton();
}
public Singleton getInstance(){
return singleton;
}
}
}
实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞,
缺点没有延迟加载。
标签:Singleton,getInstance,模式,instance,static,单例,new,public From: https://www.cnblogs.com/Gguopeng/p/18492684