写享元模式的时候,会想使用ConcurrentHashMap来保证并发,没有使用双重锁会不会有问题?但是在synchronize代码块里面需要尽量避免throw异常,希望有经验的同学能够给出解答?
1月6号补充:没有使用双重锁会有问题
享元模式UML图如下:
@Component
public class PayContextFactory extends AbstractPayContextFactory<PayContext> {//享元模式private static final Map<String, PayContext> payContexts = new ConcurrentHashMap<>();@Overridepublic PayContext getContext(Integer payType) {StrategyEnum strategyEnum =payType == 1 ? StrategyEnum.alipay :payType == 2 ? StrategyEnum.wechat :null;if (Objects.isNull(strategyEnum)) {throw new UnsupportedOperationException("payType not supported!");}//尝试从map中获取ContextPayContext context = payContexts.get(strategyEnum.name());//第一次调用if (Objects.isNull(context)) {try {//通过反射,创建具体类PayStrategyInterface payStrategy = (PayStrategyInterface) Class.forName(strategyEnum.getValue()).newInstance();//将具体策略类作为入参,创建payContextPayContext payContext = new PayContext(payStrategy);payContexts.put(strategyEnum.name(), payContext);} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new UnsupportedOperationException("get strategy failed!");}}return payContexts.get(strategyEnum.name());}
}
使用双重检查锁后的代码
@Component
public class PayContextFactory extends AbstractPayContextFactory<PayContext> {//享元模式private static final Map<String, PayContext> payContexts = new ConcurrentHashMap<>();@Overridepublic PayContext getContext(Integer payType) {StrategyEnum strategyEnum =payType == 1 ? StrategyEnum.alipay :payType == 2 ? StrategyEnum.wechat :null;if (Objects.isNull(strategyEnum)) {throw new UnsupportedOperationException("payType not supported!");}//尝试从map中获取ContextPayContext context = payContexts.get(strategyEnum.name());//第一次调用if (Objects.isNull(context)) {synchronized (payContexts) {context = payContexts.get(strategyEnum.name());if (Objects.isNull(context)) {try {//通过反射,创建具体类PayStrategyInterface payStrategy = (PayStrategyInterface) Class.forName(strategyEnum.getValue()).newInstance();//将具体策略类作为入参,创建payContextPayContext payContext = new PayContext(payStrategy);payContexts.put(strategyEnum.name(), payContext);} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {throw new UnsupportedOperationException("get strategy failed!");}}}}return payContexts.get(strategyEnum.name());}
}