设计模式之美(2)-创建型-单例模式
https://time.geekbang.org 极客时间-设计模式之美-笔记
构造函数需要是private访问权限的,这样才能避免外部通过new创建实例;
考虑对象创建时的线程安全问题;
考虑是否支持延迟加载;
考虑 getInstance() 性能是否高(是否加锁)。
1. 饿汉式
public class IdGenerator {private AtomicLong id = new AtomicLong();private static final IdGenerator idGenerator = new IdGenerator();private IdGenerator(){}public static IdGenerator getInstance(){return idGenerator;}public long getId(){return id.incrementAndGet();}}
有饿汉式,对应的,就有懒汉式。懒汉式相对于饿汉式的优势是支持延迟加载。
public class IdGeneratorV2 {private AtomicLong atomicLong = new AtomicLong(0);private static IdGeneratorV2 idGeneratorV2;private IdGeneratorV2(){}public static synchronized IdGeneratorV2 getInstance(){if(idGeneratorV2 == null){idGeneratorV2 = new IdGeneratorV2();}return idGeneratorV2;}public long getId(){return atomicLong.incrementAndGet();}}
懒汉式的缺点也是很明显,我们给getinstance()这个方法加了锁,导致这个函数并发度很低。如果这个单例类偶尔被用到,那这种实现方式还是可以接受。但是平凡的使用,那频繁的加锁、释放锁及并发度低等问题,会导致性能瓶颈。
饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。双重检测的实现方式会同时支持延迟加载,又支持高并发。
public class IdGeneratorV3 {private AtomicLong atomicLong = new AtomicLong(0);private IdGeneratorV3(){}private static IdGeneratorV3 idGeneratorV3;public static IdGeneratorV3 getInstance(){if(idGeneratorV3 == null){synchronized (idGeneratorV3.getClass()){if(idGeneratorV3 == null) {idGeneratorV3 = new IdGeneratorV3();}}}return idGeneratorV3;}public long getId(){return atomicLong.incrementAndGet();}}
public class IdGeneratorV4 {private AtomicLong atomicLong = new AtomicLong(0);private IdGeneratorV4(){}private static class SingletonHolder{private static final IdGeneratorV4 ID_GENERATOR_V_4 = new IdGeneratorV4();}public static IdGeneratorV4 getInstance(){return SingletonHolder.ID_GENERATOR_V_4;}public long getID(){return atomicLong.incrementAndGet();}}
public enum IdGeneratorV5 {INSTANCE;private AtomicLong atomicLong = new AtomicLong(0);public long getID(){return atomicLong.incrementAndGet();}}
public class BackendServer {public BackendServer(Integer serverNo, String serverAddress) {this.serverNo = serverNo;this.serverAddress = serverAddress;}private Integer serverNo = 3;private String serverAddress;private static final int SERVER_COUNT=3;private static final Map<Integer, BackendServer> BACKEND_SERVER_MAP = Maps.newHashMap();static {BACKEND_SERVER_MAP.put(1, new BackendServer(1, "127.0.0.1"));BACKEND_SERVER_MAP.put(2, new BackendServer(2, "127.0.0.2"));BACKEND_SERVER_MAP.put(3, new BackendServer(3, "127.0.0.3"));}public BackendServer getBackend(Integer serverNo){return BACKEND_SERVER_MAP.get(serverNo);}public BackendServer getRandomBackend(Integer serverNo){Random random = new Random();int i = random.nextInt(SERVER_COUNT)+1;return BACKEND_SERVER_MAP.get(i);}}
