前言
前两天在学jvm的生命周期时,在jvm的退出阶段遇到了这个问题,JVM的退出通常发生在程序正常执行结束、遇到异常或错误而终止、某个线程调用Runtime类或System类的exit方法,或者通过JNI(Java Native Interface)规范描述的JNI Invocation API来卸载JVM时。
而这里的Runtime就用了单例模式中的饿汉式,当时还不知道什么是饿汉式就先简单学习了一下。
Runtime类的部分源码:
public class Runtime { private static Runtime currentRuntime = new Runtime(); /** * Returns the runtime object associated with the current Java application. * Most of the methods of class <code>Runtime</code> are instance * methods and must be invoked with respect to the current runtime object. * * @return the <code>Runtime</code> object associated with the current * Java application. */ public static Runtime getRuntime() { return currentRuntime; } /** Don't let anyone else instantiate this class */ private Runtime() {}
单例模式
属于设计模式中的创建型模式中的一种,分为饿汉式和懒汉式等。
软件设计模式(softwaredesignpatern),又称设计模式,是一套被反复使用,多数人知晓的,经过分类编目
的,代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。
1、概念
创建型模式概念:
用于描述怎样创建对象", 创建对象",它的主要特点是将对象的创建与使用分离".(也就是解耦)GoF(四人组)书中提供了单例,原型,工厂方法,抽象工场,建造者等5种创建型模式。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。
单例模式(slngletonpattern)是java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式的结构:
有以下角色:
单例类:只能创建一个实例的类。
访问类:使用单例类。
2、饿汉式
定义:类加载就会导致该实例对象被创建
饿汉式实现方式一:静态成员变量
public class Singleton {
//首先有一个私有的构造方法
private Singleton (){}
//私有的静态的成员变量
private static Singleton instance = new Singleton();
//提供获取对象的方法
public static Singleton getInstance(){
return instance;
}
}
饿汉式实现方式二:静态代码块
public class Singleton {
//首先有一个私有的构造方法
private Singleton(){}
//私有的静态的成员变量,没有赋值
private static Singleton instance;
//在静态代码块中赋值
static {
instance = new Singleton();
}
//对外提供访问的方式
public static Singleton getInstance(){
return instance;
}
}
饿汉式的写法这样就可以了,那么我们来说下饿汉式的缺点吧
该方式在成员位置声明singleton类型的静态变量,并创建singleton类的对象instance.instance对象是随着类的加载而创建的。如果该对象足够大的话,而一直没有使用就会造成内存的浪费。
3、懒汉式
定义:类加载就不会导致该实例对象被创建,而是首次使用该对象时才会创建。
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
//如果没有创建过该对象,那么直接创建,否则直接返回
//保证创建的是同一个对象
//这种方式,如果在多线程环境下是不安全的,可以加上一个synchronized锁
if (singleton != null){
singleton = new Singleton();
}
return singleton;
}
}
这里如果加上synchronized锁,虽然实现了线程安全,但是可能会造成线程阻塞。
4、单例有哪些优点和缺点呢?
优点:
1、在内存里只有一个实例,减少了内存的开销,避免频繁的创建和销毁实例。
2、避免对资源的多重占用(比如写文件操作),提升了性能。
3、提供了对唯一实例的受控访问。
缺点:
1、不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3、从设计原则方面说,单例类的职责过重,在一定程度上违背了“单一职责原则”。
4、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
5、单例模式的使用场景:
1、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
2、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。