第517篇--Design pattern (Singleton 1)
场景
我们现在要做一个网络游戏的服务端程序,需要考虑怎么样才能承载大量的用户。在做WEB程序的时候有各种负载均衡的方案,不管是通过硬件实现还是软件实现,基本的思想就是有一个统一的入口,然后由它来分配用户到各个服务器上去。
需要考虑的问题是,即使在多线程的并发状态下,用户只能通过一个唯一的入口来分配,由此引入了Singleton模式来实现这个唯一的入口。
代码:
using System; using System.Collections.Generic; using System.Threading; namespace SingletonExample { class Program { static void Main(string[] args) { ParameterizedThreadStart ts = new ParameterizedThreadStart(EnterPlayer); for (int i = 0; i < 20; i++) { Thread t = new Thread(ts); t.Start("player" + i); } LoadBalanceServer.GetLoadBalanceServer().ShowServerInfo(); Console.ReadKey(); } /// <summary> /// 来了一个新的人,好: /// 1 进入一个LoadBalanceServer,找出负载最少的LobbyServer /// 2 进入负载最少的LobbyServer. /// </summary> /// <param name="playerName"></param> static void EnterPlayer(object playerName) { LoadBalanceServer lbs = LoadBalanceServer.GetLoadBalanceServer(); lbs.GetLobbyServer().EnterPlayer(playerName.ToString()); } } class LoadBalanceServer { private const int SERVER_COUNT = 3; /// <summary> /// 分配和控制几个LobbyServer. /// </summary> private List<LobbyServer> serverList = new List<LobbyServer>(); private static volatile LoadBalanceServer lbs; private static object syncLock = new object(); /// <summary> /// 初始化的时候,初始化3个LobbyServer(只能实例化一次), 在外面限制了不能用new实例 /// </summary> private LoadBalanceServer() { for (int i = 0; i < SERVER_COUNT; i++) { serverList.Add(new LobbyServer("LobbyServer" + i)); } } /// <summary> /// 制造一个唯一的实例 /// </summary> /// <returns></returns> public static LoadBalanceServer GetLoadBalanceServer() { if (lbs == null) { lock (syncLock) { // 一定要再次判断,不然假如有两个线程在Lock处等待,则第一个线程创建了LoadBalanceServer实例,第二个又会创建实例. if (lbs == null) { Thread.Sleep(100); lbs = new LoadBalanceServer(); } } } return lbs; } public LobbyServer GetLobbyServer() { LobbyServer ls = serverList[0]; for (int i = 1; i < SERVER_COUNT; i++) { if (serverList[i].PlayerList.Count < ls.PlayerList.Count) ls = serverList[i]; } return ls; } /// <summary> /// 最后显示出来的,都分配过了,LobbyServer /// </summary> public void ShowServerInfo() { foreach (LobbyServer ls in serverList) { Console.WriteLine("=================" + ls.ServerName + "================="); foreach (string player in ls.PlayerList) { Console.WriteLine(player); } } } } class LobbyServer { /// <summary> /// 玩家队列,每一个LobbyServer有多个玩家 /// </summary> private List<string> playerList = new List<string>(); public List<string> PlayerList { get { return playerList; } } private string serverName; public string ServerName { get { return serverName; } } public LobbyServer(string serverName) { this.serverName = serverName; } public void EnterPlayer(string playerName) { playerList.Add(playerName); } } }
http://images.cnblogs.com/cnblogs_com/lovecherry/Singleton.jpg
代码说明
LoadBalanceServer类实现了Singleton模式,也就是说无论在什么情况下,只会有一个LoadBalanceServer类的实例出现。
LobbyServer类表示大厅服务,用户进入大厅后和大厅服务进行服务,在这里我们仅仅在大厅服务里面保存了用户列表。
Singleton模式有很多实现方式,在这里使用的是双重锁定方式。对于C#来说,可能使用静态初始化方式是最简洁的,这里就不演示了。
LoadBalanceServer类的GetLobbyServer()方法负责返回一个压力最小的LobbyServer对象。
实例化LoadBalanceServer的时候Sleep了线程,目的是模拟高并发的情况,在正式代码中没有必要这样做。
何时采用
从代码角度来说,当你希望类只有一个实例的时候。
从应用角度来说,你希望有一个总管来负责某一件事情。并且这件事情的分配只能有一个人进行,如果有多个人进行肯定会弄乱。比如创建处理流水号如果有两个地方在创建的话是不是就会重复了呢?
注意事项:
这个地方要确保只执行一次,不然LobbyServer都清空了
/// <summary>
//初始化的时候,初始化3个LobbyServer(只能实例化一次,在外部不能用new实例化对象)
/// </summary>
private LoadBalanceServer()
{
for (int i = 0; i < SERVER_COUNT; i++)
{
serverList.Add(new LobbyServer("LobbyServer" + i));
}
}
下载地址:https://skydrive.live.com/#cid=6B286CBEF1610557&id=6B286CBEF1610557!673