设计模式之美(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);
}
}