设计模式——单例模式(懒汉式、饿汉式)

       单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。它分为懒汉式和饿汉式。

注意:

  • 构造器必须私有化。
  • 对外必须获得一个公有的访问方式来获得实例。

1. 饿汉式:

      顾名思义,饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。

public class Teacher {
   
	private static Teacher t=new Teacher();
	private Teacher() {
		
	}
	
	public static Teacher Get() {
		return t;
	}
}

优点:写法简单,在类加载的时候就完成实例化,避免线程同步。

缺点:没有达到懒加载的效果,若果自始至终都没有用过这个对象,就会造成内存浪费。

2 懒汉式:

      当程序第一次访问单例模式实例时才进行创建(延迟加载)。

2.1  第一种实现方式(不推荐)

public class Singleton1 {
	
    private static Singleton1 singleton;
    private Singleton1() {
    	
    }
    
    public static Singleton1 getInstance() {
    	
    	if(singleton==null) 
    	{
    	  singleton=new Singleton1();
    	}
    	
    	return singleton;
    }
}

 缺点:只能在单线程下使用,多线程下会产生多个对象。

2.2  第二种实现方式(不推荐)

public class Singleton2 {
  private static Singleton2 singleton;
  private Singleton2() {
	  
  }
  public static synchronized Singleton2 getInstance() {
	  if(singleton==null) {
		  singleton=new Singleton2();
	  }
	  return singleton;
  }
  
}

缺点:加锁进行同步,虽然可以保证单例,但效率太低,浪费大量时间。

2.3  第三种实现方式(推荐)

 著名的双重检查机制

public class Singleton3 {
   private volatile static Singleton3 singleton;
   //private static Singleton singleton;  
   private Singleton3() {
	   
   }
   
   public static Singleton3 getInstance() {
	   if(singleton==null) {
		   
		   synchronized (Singleton3.class) {
			if(singleton==null) {
				singleton=new Singleton3();
			}
		}
	   }
	   
	   return singleton;
   }
   
}

优点:保证单例的同时,也提高了效率。

注意:singleton前面要加volatile关键字来保证程序运行的有序性,否则多线程访问下可能会出现对象未初始化错误

说明:在内存中,创建一个变量需要三步:1.申请一块内存 ;2.调用构造方法初始化 ;3 分配一个指针指向这块内存

在编译原理中,有一个重要的内容叫做编译器优化,即在不改变原来语义的情况下,调整语句的执行顺序,来让程序运行的更快

因此存在这样一种情况,有两个线程A、B同时访问getInstance方法

  • A线程判断对象为空,没来得及进行第二次判断,(时间片用完了,B线程进入)
  • B线程判断对象为空,执行创建变量的3步,先申请一块内存,后分配一个指针指向这块内存,但还没有进行初始化(时间片用完了,A线程进入)
  • A线程接着执行,发现此时singleton已经不为空了,所以直接返回,但此时返回的singleton对象虽然B线程已经new了,但还没有初始化这个实例并没有构造完成,此时如果A线程使用这个实例,程序就会出现对象未初始化错误了。

2.4  第四种实现方式(推荐)

public class Singleton4 {

	private Singleton4() {
		
	}
	private static class SingletonHolder 
	{
	  private static Singleton4 singleton=new Singleton4();
	}
	
	public static Singleton4 getInstance() { 
		return SingletonHolder.singleton;
	}
	
}

       这里采用了静态内部类实例singleton对象,静态内部类相当于一个静态属性,只有在第一次加载类时才会初始化,在类初始化时,别的线程是无法进入的,因此保证了线程安全。


 

你可能感兴趣的:(设计模式)