定义:在整个软件系统中,对某个类只能存在一个对象实例
- 饿汉式 两种
-
- 静态常量、静态代码块
- 懒汉式 三种
-
- 线程不安全;线程安全,同步方法;线程安全,同步代码块
- 双重检查
- 静态内部类
- 枚举
饿汉模式:
- 构造器私有化(防止new)
- 类的内部创建对象
- 向外暴露一个静态的公共方法
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 内部创建对象
private final static SingleTon instance = new SingleTon();
// 提供一个共有的静态方法,返回实例对象
public static SingleTon getInstance(){
return instance;
}
}
// 单例模式可用,可能造成内存浪费
// 第二种写法,与上面写法相同
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 内部创建对象
private static SingleTon instance;
// 在静态代码块中创建单例
static{
instance = new SingleTon();
}
// 提供一个共有的静态方法,返回实例对象
public static SingleTon getInstance(){
return instance;
}
}
在main中使用时,直接通过SingleTon.getInstance()获取对象实例,获取到的两个对象实例是同一个对象实例
- 在类装载的时候就完成了实例化,没有达到懒加载的效果;如果从始至终没有用到过这个实例,则会造成内存浪费(类装载的情况很多)
懒汉式:
- 用到才去创建,不用到就不会去创建
// 第一种懒汉式,线程不安全的
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 内部创建对象
private static SingleTon instance;
// 提供一个共有的静态方法,当使用该方法时,才去创建一个实例
public static SingleTon getInstance(){
if(instance == null){
instance = new SingleTon();
}
return instance;
}
}
// ------ 开发时不能使用,有潜在的风险 ------
================================================================
// 第二种懒汉式,加 synchronized 实现线程安全
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 内部创建对象
private static SingleTon instance;
// 提供一个共有的静态方法,当使用该方法时,才去创建一个实例
public static synchronized SingleTon getInstance(){
if(instance == null){
instance = new SingleTon();
}
return instance;
}
}
// 本来该类只需要执行一次,
// 但是有了synchronized后,每次获取实例都要进行一次同步
// ------ 开发时不推荐使用,效率太低 ------
================================================================
// 第三种懒汉式
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 内部创建对象
private static SingleTon instance;
// 提供一个共有的静态方法,当使用该方法时,才去创建一个实例
public static SingleTon getInstance(){
if(instance == null){
synchronized(SingleTon.class){
instance = new SingleTon();
}
}
return instance;
}
}
// 并不能起到线程安全的作用,不能用
双重检查:
解决线程安全的问题,解决了效率的问题
class SingleTon{
private static volatile SingleTon instance;
// 构造器私有化
private SingleTon(){}
public static SingleTon getInstance(){
if(instance == null){
synchronized(SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
}
return instance;
}
}
// 推荐使用
静态内部类:
外部类装载,静态内部类并不会被立即装载;只有在调用getInstance
方法时才会装载,而且只装载一次。(线程是安全的)
class SingleTon{
// 构造器私有化
private SingleTon(){}
// 写一个静态内部类,该类中有一个静态属性 SingleTon
private static class SingletonInstance{
private static final SingleTon INSTANCE = new SingleTon();
}
// 提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE
public static SingleTon getInstance(){
return SingletonInstance.INSTANCE;
}
}
// 效率高,推荐使用
枚举的方式实现单例模式
enum Singleton{
INSTANCE;
public void sayOk(){
System.out.println("ok~");
}
}
public static void main(String[] args){
Singleton singleton_01 = Singleton.INSTANCE;
Singleton singleton_02 = Singleton.INSTANCE;
// 以上两个为一个对象,返回的hashCode相同
}
// 推荐使用
// 借助jdk1.5中添加的枚举来实现单例模式,避免了线程同步,防止反序列化重建对象
项目实例
Java中的 Runtime 使用的就是饿汉式
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime(){
return currentRuntime;
}
推荐使用:饿汉式、双重检查、静态内部类、枚举
使用场景:
- 频繁进行创建和销毁的对象
- 创建对象时耗时过多或耗费资源过多,担忧经常使用到的对象
- 工具类对象
- 频繁访问数据库或文件的对象