确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。比如:线程池、缓存、日志对象。
2、单例模式的特点①单例类只能有一个实例。
②单例类必须自己创建自己的唯一实例。
③单例类必须给所有其他对象提供这一实例。
(1)懒汉式——线程不安全
(2)饿汉式——天生线程安全
/**
* 懒汉式单例类——线程不安全
* 在第一次调用的时候实例化自己
*/
public class DanLi {
//通过将构造方法限定为private避免了类在外部被实例化,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,
// 只有通过该类提供的静态方法getDanLi来得到该类的唯一实例
private DanLi() {
}
//创建静态对象
private static DanLi danLi = null;
//在该类内提供一个静态方法
// 当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。
public static DanLi getDanLi() {
if (danLi == null) {
danLi = new DanLi();
}
return danLi;
}
}
以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全。
方式一:在getInstance方法上加同步public static synchronized DanLi getDanLi() {
if (danLi == null) {
danLi = new DanLi();
}
return danLi;
}
方式二:双重检查锁定
public static DanLi getDanLi() {
if (danLi == null) {
synchronized (DanLi.class) {
if (danLi == null) {
danLi = new DanLi();
}
}
}
return danLi;
}
方式三:静态内部类
/**
* 懒汉式单例类——线程安全
* 在第一次调用的时候实例化自己
*/
public class DanLi {
//构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,
// 只有通过该类提供的静态方法来得到该类的唯一实例
private DanLi() {
}
//创建静态内部类
private static class LazyHolder {
private static final DanLi DAN_LI = new DanLi();
}
//创建静态对象
private static DanLi danLi = null;
//在该类内提供一个静态方法
// 当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。
public static final DanLi getDanLi() {
return LazyHolder.DAN_LI;
}
}
饿汉式单例——线程安全
/**
* 饿汉式单例类.在类初始化时,已经自行实例化
* 饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的
*/
public class EHanDanLi {
//创建私有的构造方法
private EHanDanLi() {
}
//在类创建的同时就已经创建好一个静态的对象供系统使用
private static final EHanDanLi E_HAN_DAN_LI = new EHanDanLi();
//静态工厂方法
public static EHanDanLi geteHanDanLi() {
return E_HAN_DAN_LI;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。
饿汉式和懒汉式区别饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题;
懒汉式本身是非线程安全的。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)