Java设计模式之——单例模式(5种单例类型)
单例模式是一种创建型设计模式,它可以保证一个类只有一个实例,并提供全局访问点。单例模式在实际开发中经常使用,可以避免多个实例引起的资源浪费和同步问题。
根据实现方式的不同,单例模式可以分为以下几种分类:
1. 饿汉式单例模式
饿汉式单例模式是指在类加载时就创建了单例对象,因此在调用时不需要再创建对象,直接使用即可。这种实现方式比较简单,但是在某些情况下可能会造成资源浪费。
2. 懒汉式单例模式
懒汉式单例模式是指在调用时才创建单例对象,这种实现方式避免了资源浪费,但是需要注意线程安全问题。
3. 双重检查锁单例模式
双重检查锁单例模式是指在懒汉式单例模式的基础上加入了双重检查锁机制,可以保证线程安全,同时也避免了资源浪费。
4. 静态内部类单例模式
静态内部类单例模式是指将单例对象作为静态内部类的一个静态变量,这种实现方式可以保证线程安全,同时也可以避免资源浪费。
5. 枚举单例模式
枚举单例模式是指将单例对象定义为一个枚举类型,这种实现方式可以保证线程安全,同时也可以防止反射和序列化攻击。
下面是配合源码的讲解:
1. 饿汉式单例模式
饿汉式单例模式是指在类加载时就创建了单例对象,因此在调用时不需要再创建对象,直接使用即可。这种实现方式比较简单,但是在某些情况下可能会造成资源浪费。
下面是一个简单的饿汉式单例模式的示例代码:
```java
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// 私有化构造方法
}
public static Singleton getInstance() {
return instance;
}
// 其他业务方法
}
```
上面的代码中,我们定义了一个 `Singleton` 类,并在类加载时创建了一个单例对象 `instance`。`instance` 使用 `private static final` 修饰,表示它是一个私有的静态常量,其他类不能修改它的值。
`Singleton` 的构造方法被私有化,这样其他类就无法通过 `new` 关键字来创建 `Singleton` 的实例。
`getInstance` 方法返回 `instance` 对象,这样其他类可以通过 `Singleton.getInstance()` 来获取单例对象。
2. 懒汉式单例模式
懒汉式单例模式是指在调用时才创建单例对象,这种实现方式避免了资源浪费,但是需要注意线程安全问题。
下面是一个简单的懒汉式单例模式的示例代码:
```java
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// 私有化构造方法
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// 其他业务方法
}
```
上面的代码中,我们定义了一个 `Singleton` 类,并使用一个静态变量 `instance` 来保存单例对象。在 `getInstance` 方法中,我们首先判断 `instance` 是否为 `null`,如果是则创建一个新的 `Singleton` 对象,并将其赋值给 `instance` 变量。由于 `getInstance` 方法是 `synchronized` 的,所以可以保证线程安全。
需要注意的是,懒汉式单例模式可能存在性能问题,因为每次调用 `getInstance` 方法都需要进行线程同步,这会影响程序的性能。为了避免这个问题,可以使用双重检查锁单例模式。
3. 双重检查锁单例模式
双重检查锁单例模式是指在懒汉式单例模式的基础上加入了双重检查锁机制,可以保证线程安全,同时也避免了资源浪费。
下面是一个简单的双重检查锁单例模式的示例代码:
```java
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
// 私有化构造方法
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
// 其他业务方法
}
```
上面的代码中,我们使用了 `volatile` 关键字来保证 `instance` 变量的可见性。在 `getInstance` 方法中,我们首先判断 `instance` 是否为 `null`,如果是则进入同步块。在同步块中,我们再次判断 `instance` 是否为 `null`,如果是则创建一个新的 `Singleton` 对象,并将其赋值给 `instance` 变量。由于使用了双重检查锁机制,所以可以保证线程安全。
需要注意的是,双重检查锁单例模式在多线程环境下仍然可能存在问题,因为在某些情况下可能会出现指令重排的情况。为了避免这个问题,可以将 `instance` 变量声明为 `volatile`,这样可以禁止指令重排。
4. 静态内部类单例模式
静态内部类单例模式是指将单例对象作为静态内部类的一个静态变量,这种实现方式可以保证线程安全,同时也可以避免资源浪费。
下面是一个简单的静态内部类单例模式的示例代码:
```java
public class Singleton {
private Singleton() {
// 私有化构造方法
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
// 其他业务方法
}
```
上面的代码中,我们定义了一个 `Singleton` 类,并将单例对象作为静态内部类 `SingletonHolder` 的一个静态变量。在 `getInstance` 方法中,我们直接返回 `SingletonHolder.instance`,这样就可以获取到单例对象。
由于静态内部类只会在第一次使用时才会被加载,所以可以保证线程安全。而且由于单例对象是在静态内部类中创建的,所以可以避免资源浪费。
5. 枚举单例模式
枚举单例模式是指将单例对象定义为一个枚举类型,这种实现方式可以保证线程安全,同时也可以防止反射和序列化攻击。
下面是一个简单的枚举单例模式的示例代码:
```java
public enum Singleton {
INSTANCE;
// 其他业务方法
}
```
上面的代码中,我们定义了一个枚举类型 `Singleton`,其中 `INSTANCE` 就是单例对象。由于枚举类型只会被加载一次,所以可以保证线程安全。
由于枚举类型的构造方法是私有化的,所以无法通过反射来创建枚举类型的实例,从而避免了反射攻击。同时,枚举类型的序列化和反序列化也是由 JVM 自动完成的,所以可以避免序列化攻击。