介绍
单例模式是软件设计模式之一,保证一个类只有一个实例。实现这样的需求的方法是:构造方法私有,在类内创建一个静态对象,并创建一个公有的静态方法来访问这个对象。
单例模式的常见的实现模式有饿汉模式和懒汉模式。
饿汉模式
特点:在类定义的时候就实例化,线程安全。但是占用内存空间。
应用场景:在访问量比较大或者多线程的时候采用
实例:
public class Singleton {
private Singleton(){
System.out.println("我是单例模式");
}
private static Singleton ehan = new Singleton();
public static Singleton getInstance(){
System.out.println("我是饿汉模式");
return ehan;
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
Singleton one= Singleton.getInstance();
Singleton two = Singleton.getInstance();
if (one==two){
System.out.println("我确实是单例");
}
}
}
输出结果:
懒汉模式
特点:太懒了,等到第一次调用的时候才进行实例化,线程不安全(如果唯一实例未被创建,有两条线程同事访问创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,这样就违反了单例模式中实例唯一的原则。)所以懒汉模式需要以加锁的方式来保证安全。
应用场景:访问量小的时候采用
实例:
public class Singleton {
private Singleton(){
System.out.println("我是单例模式");
}
private static Singleton lanhan;
public static synchronized Singleton getInstance(){
if (lanhan==null){
lanhan= new Singleton();
System.out.println("我是懒汉模式");
}
return lanhan;
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
Singleton one= Singleton.getInstance();
Singleton two = Singleton.getInstance();
if (one==two){
System.out.println("我确实是单例");
}
}
}
输出结果
对比
饿汉模式:
优点:没有加锁,执行效率高,线程安全
缺点:类加载时就实例化,浪费内存
懒汉模式:
优点:第一次调用才实例化,避免浪费内存
缺点:必须加锁才能保证线程安全,加锁影响效率。
扩展
单例模式还有双重检索机制、静态内部类和枚举类实现。
双重检索机制
实现复杂,但是线程安全,且执行效率高。
public class DoublecheckSingleton {
private DoublecheckSingleton() {
System.out.println("我是单例模式");
}
private static volatile DoublecheckSingleton doublecheckSingleton;
public static DoublecheckSingleton getInstance() {
if (doublecheckSingleton == null) {
synchronized (DoublecheckSingleton.class) {
if (doublecheckSingleton == null) {
doublecheckSingleton = new DoublecheckSingleton();
System.out.println("我是双重检索机制");
}
}
}
return doublecheckSingleton;
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
DoublecheckSingleton one= DoublecheckSingleton.getInstance();
DoublecheckSingleton two = DoublecheckSingleton.getInstance();
if (one==two){
System.out.println("我确实是单例");
}
}
}
输出结果
静态内部类实现
使用静态域实现延迟加载。
public class Singleton {
private Singleton(){
System.out.println("我是单例模式");
}
static class Jint{
private static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
System.out.println("我是静态内部类实现");
return Jint.INSTANCE;
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
Singleton one= Singleton.getInstance();
Singleton two = Singleton.getInstance();
if (one==two){
System.out.println("我确实是单例");
}
}
}
输出结果
枚举类实现
最简单的实现
public enum Singleton {
INSTANCE;
public void method(){
System.out.println("我是枚举类单例模式");
}
}
测试代码
public class TestMain {
public static void main(String[] args) {
Singleton one= Singleton.INSTANCE;
Singleton two = Singleton.INSTANCE;
if (one==two){
System.out.println("我确实是单例");
one.method();
two.method();
}
}
}
输出结果