一、基本特点
如何防止创建多个实例:构造方法设置为私有,使得外部无法直接new出实例
基本组成:a)一个静态的和自身类型相同的成员对象
b)私有的构造方法
c)获取实例的公有方法,供外部调用,以返回实例
二、懒汉式
特点:类被加载时不创建实例,getInstance方法第一次被调用时才创建实例
类代码:
public class LazySingleton { /** * 静态的和自身类型相同的成员对象 */ private static LazySingleton theLazySingleton=null; /** * 构造方法设置为私有,保证无法从外部new出实例 * LazySingleton myLazySingleton=new LazySingleton();这样的语句就无法通过编译 */ private LazySingleton(){} /** * 供外部调用的获取实例的方法,会在第一次调用时初始化实例 */ public static LazySingleton getInstance(){ if(theLazySingleton==null){ System.out.println("懒汉式单例,第一次调用,先创建,再返回实例!"); theLazySingleton=new LazySingleton(); }else{ System.out.println("懒汉式单例,已不是第一次调用,直接返回实例!"); } return theLazySingleton; } }
主函数:
public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("开始测试单例模式!"); //尽管使用了两个引用名,实际上指向的是内存中同一个实例 LazySingleton myLazySingleton_A, myLazySingleton_B; myLazySingleton_A=LazySingleton.getInstance(); myLazySingleton_B=LazySingleton.getInstance(); }
运行结果:
三、饿汉式
特点:类被加载时就创建实例
类代码:
public class HungrySingleton { private static final HungrySingleton theHungrySingleton=new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ System.out.println("饿汉式单例,实例已在类加载时被创建,故可直接返回实例!"); return theHungrySingleton; } }
主函数:
public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("开始测试单例模式!"); HungrySingleton myHungrySingleton=HungrySingleton.getInstance(); }
运行结果:
四、多线程环境下的单例模式
A)线程安全的单例:
1、效率较高线程安全单例(常用方式)
“静态内部类”只在getInstance()方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的(实现线程安全)
//静态内部类实现懒汉式 public class Singleton { private static class SingletonHolder{ //单例变量 private static Singleton instance = new Singleton(); } //私有化的构造方法,保证外部的类不能通过构造器来实例化。 private Singleton() { } //获取单例对象实例 public static Singleton getInstance() { System.out.println("我是内部类单例!"); return SingletonHolder.instance; } }
2、效率较低线程安全单例
a)懒汉式,静态方法getInstance前加“类锁”
缺点:每次获取实例时都会对类进行加锁操作,影响性能
实际只需第一次instance==null时加类锁,防止内存中创建了两个实例。
public class Singleton { //单例实例变量 private static Singleton instance = null; //私有化的构造方法,保证外部的类不能通过构造器来实例化 private Singleton() {} //获取单例对象实例 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } System.out.println("我是同步法懒汉式单例!"); return instance; } }
b)饿汉式
缺点: 一些未必需要加载的模块会每次都被加载,影响整个系统初次加载速度
public class Singleton { //单例变量 ,static的,在类加载时进行初始化一次,保证线程安全 private static Singleton instance = new Singleton(); //私有化的构造方法,保证外部的类不能通过构造器来实例化。 private Singleton() {} //获取单例对象实例 public static Singleton getInstance() { System.out.println("我是饿汉式单例!"); return instance; } }