学习笔记
23种设计模式:
创建型模式(5):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式
结构性模式(7):适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式
行为型模式(11):策略模式,观察者模式,模板方法模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式
问:
为什么要使用单例模式
单例存在哪些问题
单例与静态类的区别
有何替代的解决方案
要实现一个单例模式需要关注几个点:
1.构造器需要是private访问权限的,避免外部new对象。
2.考虑对象创建时的线程安全问题。
3.考虑是否支持延迟加载
4.考虑getInstance()性能是否高(是否加锁)。
单例设计模式:理解起来就是,一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫做单例设计模式,简称单例模式。
对象锁,对同一个对象的执行有效,不同对象的执行是无效的,加锁必须是多个线程共用一把锁才会起作用。
类锁,让所有对象共享一把锁。避免了不同对象之间同时调用函数,导致线程并发问题。实现如下
public class IdGenerator {
private static final IdGenerator instance = new IdGenerator();
private AtomicLong id = new AtomicLong();
private IdGenerator(){
}
/**
* @Description:类加载的时候就完成了初始化
*/
public static IdGenerator getInstance() {
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
单例模式:
public class IdGeneratorError {
private static AtomicLong id = new AtomicLong();
public long getId() {
return id.incrementAndGet();
}
}
业务概念上来说,如果有些数据在系统中只应保存一份,那就比较适合单例模式。比如配置信息类。
1.饿汉式:
饿汉式实现方式,在类加载时,instance静态实例就已经创建并初始化好了,所以,instance实例的创建过程是线程安全的。不过这样的方式不支持延时加载(真正用到时,再创建实例)。
2.懒汉式
支持延时加载,不过加了synchronized,导致并发度低,频繁调用有性能瓶颈。
public class IdGeneratorLazy {
private AtomicLong id = new AtomicLong();
private static IdGeneratorLazy instance = null;
private IdGeneratorLazy() {
}
/**
* @Description:懒汉模式的缺点就是要在getInstance方法上加个锁,导致并发度低。
* 如果这个方法被频繁调用,那么频繁的加锁和释放锁以及并发度低会造成性能瓶颈。
*/
public static synchronized IdGeneratorLazy getInstance() {
if (instance == null) {
instance = new IdGeneratorLazy();
}
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
3.双重检测
支持延时加载和高并发。方式一:
public class IdGenetatorDoubleTest {
private static AtomicLong id = new AtomicLong();
private static volatile IdGenetatorDoubleTest instance;
private IdGenetatorDoubleTest(){
}
public static IdGenetatorDoubleTest getInstance() {
if (instance == null) {
synchronized(IdGenetatorDoubleTest.class) {
if (instance == null) {
instance = new IdGenetatorDoubleTest();
}
}
}
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
方式二:
public class IdGenetatorDoubleTest {
private static AtomicLong id = new AtomicLong();
private static volatile IdGenetatorDoubleTest instance;
private IdGenetatorDoubleTest(){
}
public static IdGenetatorDoubleTest getInstance() {
IdGenetatorDoubleTest temp = instance;
if (temp == null) {
synchronized(IdGenetatorDoubleTest.class) {
temp = instance;
if (null == temp) {
temp = new IdGenetatorDoubleTest();
instance = temp;
}
}
}
return temp;
}
public long getId() {
return id.incrementAndGet();
}
}
4.静态内部类
当外部类被加载时,内部类并不会被加载,只有当调用getInstance方法时,内部类才会被调用。instance的线程安全和唯一性由JVM保证,所以这种方式的单例,保证了线程安全,又做到延时加载。这一部分有待深入探究
public class IdGeneratorInnerClass {
private AtomicLong id = new AtomicLong();
private IdGeneratorInnerClass(){
}
private static class SingletonHolder {
private static final IdGeneratorInnerClass instance = new IdGeneratorInnerClass();
}
public static IdGeneratorInnerClass getInstance() {
return SingletonHolder.instance;
}
public long getId() {
return id.incrementAndGet();
}
}
5.枚举
怎么形容呢,就是有点懵逼
public enum IdGeneratorEnum {
;
private AtomicLong id = new AtomicLong();
public long getId() {
return id.incrementAndGet();
}
}