一.简介
1.分类:创建型设计模式
2.定义:在内存中只含有一个对象,该对象自行创建,外部不能创建该对象
3.适用场合:在应用程序的整个生命周期中,对象是有一个实例的时候使用单例模式。单例模式总是在第一次被访问时初始化
直到应用程序退出之前,会一直使用这一个实例。
4.如何确保类在内存中只有一个对象
构造方法私有化
在成员区给出该对象的引用(必须私有化,静态)
写一个公有的静态的获取实例的方法
二.饿汉式
随着类的加载而创建对象
public class EHan {
// 1. 饿汉式:在成员区就创建对象(随着类的加载而创建对象)
private EHan() {
}
private static EHan eHan = new EHan();
public static EHan geteHan(){
return eHan;
}
}
三.懒汉式
在第一次访问类时创建对象
版本1:
public class LanHan {
private LanHan() {
}
private static LanHan lanHan;
public static LanHan getLanHan(){
if(lanHan==null){
lanHan = new LanHan();
}
return lanHan;
}
}
(1)版本1出现的问题:在多线程环境中,存在线程安全问题,可能会创建多个对象
解决办法:加锁
版本2:
public class LanHan {
private LanHan() {
}
private static LanHan lanHan;
public static synchronized LanHan getLanHan(){//同步方法
if(lanHan==null){
lanHan = new LanHan();
}
return lanHan;
}
}
(2)版本2出现的问题:在第二个版本中,在需要用到实例的时候才去创建对象,每一次访问该方法就要获取进程锁,
使用成本高,然而其实我们只需要在第一次创建你实例的时候使用锁
解决办法:使用同步代码块
版本3:
public class LanHan {
private LanHan() {
}
private static LanHan lanHan;
public static LanHan getLanHan(){
if(lanHan==null){
synchronized (lanHan){
lanHan = new LanHan();
}
}
return lanHan;
}
}
(3)版本3出现的问题:以上的代码依然是线程不安全的,考虑一下场景:当线程1进入同步代码块中,还没有实例化对象时,线程被抢占,另一个线程进入if语句块,第二个线程需要等待第一个线程完成之前的运算,但是仍然会创建两个不同的实例。
解决办法:使用双重同步锁
版本4:
public class LanHan {
private LanHan() {
}
private static LanHan lanHan;
public static synchronized LanHan getLanHan(){
if(lanHan==null){
synchronized (lanHan){
lanHan = new LanHan();
}
}
return lanHan;
}
}
四.扩展
Runtime类:使用的单例模式中饿汉式的思想
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}