单例模式
定义
Ensure a class has only one instance, and provide a global point of access to it.
(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例)
创建方式
创建方式分为饿汉式、懒汉式、双重检查、静态内部类、枚举等。
饿汉式
- 静态属性创建
/**
* 采用饿汉式创建单例
* 使用静态属性,如果创建后不使用,会有内存浪费
*/
class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
- 静态代码块创建
/**
* 使用饿汉式创建单例对象
* 采用静态代码块实现
*/
class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton(){}
public static Singleton getInstance() {
return instance;
}
}
懒汉式
- 代码示例
/**
* 使用懒汉式创建单例对象,会出现线程并发问题,不推荐使用
*/
class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 在1的基础上优化如下
/**
* 使用懒汉式创建单例对象
* 解决了线程并发问题,但效率低
*/
class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 在2的基础上提升效率
/**
* 懒汉式创建单例,线程安全,推荐使用
* volatile作用:
* 1) 多线程间的数据可见性
* 2) 防止指令重排
* 如果不加volatile,可能会得到一个半初始化的对象(当然这种情况比较少见)
*/
class Singleton {
private static volatile Singleton instance;
// 对象创建比较耗时,在多线程并发时,可能对象的属性只初始化了一部分(半初始化)
private Singleton(){
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
// 异常信息
}
}
public static Singleton getInstance() {
// 说明:
// 第一个线程拿到锁后,创建对象,执行构造方法。但是只初始化到一半时,第二个线程进来判断instance == null,发现instance不为空,所以就直接返回该对象,但是这时的对象只初始化了一半(半初始化)。
// 这样就会有问题,所以要加volatile关键字,防止指令重排,就不会有这个问题了。
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类
代码示例
/**
* 静态内部类实现单例,线程安全,推荐使用
*/
class Singleton {
private Singleton() {}
private static class SingletonInstance {
public static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
测试类
public class SingletonTest {
public static void main(String[] args) {
Runnable r = () -> System.out.println(Singleton.getInstance());
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
service.execute(r);
}
service.shutdown();
}
}
枚举
代码示例
/**
* 枚举实现单例,线程安全,推荐使用
*/
enum Singleton {
INSTANCE
}
// 测试类
public class SingletonTest {
public static void main(String[] args) {
Runnable r = () -> System.out.println(Singleton.INSTANCE);
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
service.execute(r);
}
service.shutdown();
}
}