概念
单例模式 ,顾名思义就是只有一个实例,并且她自己负责创建自己的对象,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象
单:是指唯一
例:是指实例
要点
- 类中只有一个实例
- 构造器必须私有化
- 必须是这个类自行创建
- 含有一个该类的静态变量来存储这个唯一的实例
- 必须自行向整个系统提供这个实例
- 对外提供获取该实例的方式(直接暴露) (用静态变量的get方法)
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。
常见形式
-
饿汉式:直接创建对象,不存在线程安全问题
- 直接实例化饿汉式(简单直接)
- 枚举式(最简洁)
- 静态代码块饿汉式(适合复杂实例化)
-
懒汉式:延迟创建对象,存在线程安全问题
- 线程不安全(适用单线程)
- 线程安全(适用于多线程)
- 静态内部类(适用于多线程)
代码实现
- 饿汉式
一、直接实例化
/**
* 饿汉式
* 直接实例化
* 不管是否需要都会自动自动创建对象
*/
public class SingleTon {
/**
* 私有化构造器
*/
private SingleTon(){
}
public static final SingleTon singleTon = new SingleTon();
}
二、枚举法
/**
* 饿汉式
* 枚举类
*/
public enum Singleton {
SINGLETON;
}
三、静态代码块
/**
* 饿汉式
* 静态代码块
*/
public class Singleton {
public static final Singleton SINGLETON;
/**
* 私有化构造器
*/
private Singleton(){
}
static {
//可以添加配置文件等
SINGLETON = new Singleton();
}
}
- 懒汉式
一、单线程(线程不安全)
/**
* 懒汉式
* 线程不安全
*/
public class Singleton {
/**
* 私有化构造器
*/
private Singleton(){
}
//声明对象
private static Singleton singleton;
//通过方法获取单例对象
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
二、线程安全
/**
* 懒汉式
* 线程安全
*/
public class Singleton {
/**
* 私有化构造器
*/
private Singleton() {
}
//声明对象
private static Singleton singleton;
//通过方法获取单例对象
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
考虑到java中双重检查锁问题(参考如下):
java中双重检查锁
代码修改如下:
/**
* 懒汉式
* 线程安全
*/
public class Singleton {
/**
* 私有化构造器
*/
private Singleton() {
}
//声明对象
private volatile static Singleton singleton;
//通过方法获取单例对象
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
三、静态内部类
/**
* 懒汉式
* 静态内部类
*/
public class Singleton {
/**
* 私有化构造器
*/
private Singleton(){
}
//静态内部类中创建,并不会一开始就分配内存空间
private static class Inner{
public static final Singleton SINGLETON = new Singleton();
}
//调用方法的时候再调用内部类实例化对象
public static Singleton getInstance(){
return Inner.SINGLETON;
}
}
测试懒汉式的线程安全
/**
* 懒汉式
* 线程安全
*/
public class Singleton {
/**
* 私有化构造器
*/
private Singleton() {
}
//声明对象
private static Singleton singleton;
//通过方法获取单例对象
public static Singleton getSingleton() {
// 线程安全
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new Singleton();
}
}
}
return singleton;
}
// public static Singleton getSingleton() {
// //线程不安全
// if (singleton == null) {
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// singleton = new Singleton();
// }
// return singleton;
// }
}
class SingletonTest extends Thread{
@Override
public void run() {
Singleton singleton = Singleton.getSingleton();
System.out.println(singleton);
}
public static void main(String[] args) {
new SingletonTest().start();
new SingletonTest().start();
}
}