单例模式实战

作者读单例模式最佳实践文章有感,通过学习和开发对单例模式有更多了解。介绍了单例模式在高并发下需考虑诸多因素,还阐述其应用场景,如数据库连接池、线程池等,最后给出利用单例模式连接MongoDB、ZK的实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        读最近同学发的一篇文章,单例模式最佳实践:https://www.jianshu.com/p/b08fdc6f86a1 有感。以前学过单例,没有实战经验,并不知道它在程序优化的方面有很大的作用。最近通过一段时间的学习和开发,对单例模式有了更多的了解。

 

                                                                                                                                    ----------不断学习才能跟上大神的脚步。

单例模式在高并发情况下还需要考虑很多东西,此篇只做自己参考

应用场景:

1、数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

2、多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

3、Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~

4、Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

实例:(自己加上私有化的构造函数)

1、利用单例模式连接MongDB

public class MongoUtils {
    private MongoUtils(){}
	private static MongoDBDao componentDao = MongoUtils.getComponentMongDbDao();
    public static MongoDBDao getComponentMongDbDao() {
        // 获取mongo-component数据源,建立MongoDB连接池和MongoDBTemplate等封装的操作
        return MongoDB.getMongoDBDao("mongo-component");
	}
}
2、初始化redis集群工具类
public class GedisUtils {
	private static GedisCommands gedis;

	public static volatile GedisCommands getInstance() {
		if (gedis != null) {
			return gedis;
		}
		log.info("初始化Redis");
		try {
			synchronized (GedisUtils.class) {
				if (gedis == null) {
					if (EotBatchProperties.private_deploy) {
						log.info("开始初始化单点Redis..addr=" + Properties.private_redis_addr);
						gedis = GedisCommandsFactory.INSTANCE.getRedisCommand(Constant.PRIVATE_REDIS_TAG,
								Properties.private_redis_addr);
					} else {
						log.info("开始初始化Redis集群");
						GedisPoolConfig config = new GedisPoolConfig();
						config.setMaxTotal(Properties.redis_conn_max_total);
						gedis = GedisCommandsFactory.INSTANCE.getClusterCommand(Constant.PRIVATE_REDIS_TAG, "",
								config);
					}
				}
			}
		} catch (Exception e) {
			log.error("Gedis初始化过程出错,cause=" + ThrowableUtils.cause(e));
			System.exit(1);
		}
		return gedis;
	}
}
public enum GedisCommandsFactory {
    INSTANCE;

    private static ConcurrentHashMap<String, GedisCommands> singlePools = new ConcurrentHashMap();
 public GedisCommands getRedisCommand(String tag, String id, GedisPoolConfig poolConfig) {
        if (id != null && !id.trim().equals("")) {
            String[] temp = id.trim().split(":");
            if (temp.length != 3) {
                RedisLog.info("非法的参数,id = " + id);
                return null;
            } else {
                String key = GedisConstants.APPCODE + "-" + tag + "-" + id.trim();
                GedisCommands proxy = (GedisCommands)singlePools.get(key);
                if (proxy == null) {
                    proxy = GedisInitialize.getInstance().getSingleCommand(key, new GedisCommandsFactory.RedisConnInfo(tag, id, poolConfig));
                    if (proxy == null) {
                        return null;
                    }
//在此处可以保证单例

                    GedisCommands currentProxy = (GedisCommands)singlePools.putIfAbsent(key, proxy);
                    if (currentProxy != null) {
                        proxy = currentProxy;
                    }
                }

                return proxy;
            }
        } else {
            RedisLog.info("获取redis连接池时id为空");
            return null;
        }
    }
}

 

3、ZK的连接

public class ZkClientHolder {
	private static CuratorFramework client = CuratorFrameworkFactory.builder().defaultData(null)
			.connectString(ZkProperties.getZkAddress()).retryPolicy(new RetryNTimes(12, 5000)).build();
	private static AtomicBoolean startup = new AtomicBoolean(false);
	private static CountDownLatch countDownLatch = new CountDownLatch(1);

    private ZkClientHolder(){}
	public static CuratorFramework getInstance() {
		return client;
	}

	public static void startup() {
		//仅执行一次
		if (startup.compareAndSet(false, true)) {
			initZkClient();
		}
	}

	private static void initZkClient() {
		client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
			@Override
			public void stateChanged(CuratorFramework client, ConnectionState newState) {
				if (newState.isConnected()) {
					countDownLatch.countDown();
					log.info("Zookeeper连接成功");
				} else {
					log.error("Zookeeper连接丢失,重连中...");
				}
			}
		});
		if (client.getState() == CuratorFrameworkState.LATENT) {
			client.start();
			//阻塞直接连接成功或超时
			try {
				if (!countDownLatch.await(60, TimeUnit.SECONDS)) {
					// 创建连接失败,记录日志并退出应用
					log.error("Zookeeper连接创建失败,超时,退出应用");
					System.exit(1);
				}
			} catch (InterruptedException e) {
				log.error("Zookeeper连接动作被中断,退出应用");
				System.exit(1);
			}
		} else if (client.getState() == CuratorFrameworkState.STOPPED) {
			log.error("Zookeeper连接创建失败,连接已关闭,退出应用");
			System.exit(1);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_270490096

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值