一、概念
单例模式(Singleton),也叫单子模式,是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候,整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,显然,这种方式简化了在复杂环境下的配置管理。
特别地,在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。事实上,这些应用都或多或少具有资源管理器的功能。例如,每台计算机可以有若干个打印机,但只能有一个 Printer Spooler(单例) ,以避免两个打印作业同时输出到打印机中。再比如,每台计算机可以有若干通信端口,系统应当集中 (单例)管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
综上所述,单例模式就是为确保一个类只有一个实例,并为整个系统提供一个全局访问点的一种方法。
二、实现
2.1 饿汉式(静态常量)
package example01;
/**
* 第一种方式:
* 静态常量饿汉式
* 缺点:不管用不用到都实例化,造成资源浪费
*/
public class SingletonTest01 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
// 构造器私有化,外部不能new
private Singleton (){
}
// 创建实例对象
private final static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
2.2 饿汉式(静态代码块)
package example02;
/**
* 第二种方式:
* 静态代码块饿汉式
* 缺点:不管用不用到都实例化,造成资源浪费
*/
public class SingletonTest02 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
// 构造器私有化,外部不能new
private Singleton (){
}
private static Singleton instance;
static {
// 在静态代码块里创建单例对象
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
2.3 懒汉式(线程不安全)
package example03;
/**
* 第三种方式:
* 饿汉式:用到时才实例化
* 线程不安全
*/
public class SingletonTest03 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton(){}
// 提供一个静态公有方法,使用时才加载
public static Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
2.4 懒汉式(线程安全,同步方法)
package example04;
/**
* 第四种方式:
* 懒汉式
* 线程安全
* 缺点:效率太低
*/
public class SingletonTest04 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton(){}
// 提供一个静态公有方法,家兔同步处理的代码,解决线程不安全问题
public static synchronized Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
2.5 双重检查
package example05;
/**
* 第五种方式(推荐):
* 双重检查
*/
public class SingletonTest05 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
/// volatile方式指令重排
private static volatile Singleton instance;
private Singleton(){}
// 提供一个静态公有方法,加入双重检查代码。解决线程不安全问题和懒加载问题
public static synchronized Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}
}
2.6 静态内部类
package example06;
/**
* 第六种方式(推荐):
* 静态内部类
*/
public class SingletonTest06 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
/// volatile方式指令重排
private static volatile Singleton instance;
private Singleton(){}
// 写一个静态内部类
private static class SingleInstance{
private static final Singleton INSTANCE = new Singleton();
}
// 提供一个静态公有方法,返回SingleInstance.INSTANCE
public static Singleton getInstance(){
return SingleInstance.INSTANCE;
}
}
2.7 枚举类
package example07;
/**
* 枚举类
* 推荐使用
*/
public class SingletonTest07 {
public static void main(String[] args) {
// 测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
enum Singleton {
INSTANCE;
public static Singleton getInstance(){
return Singleton.INSTANCE;
}
}