確保一個類別只有一個實例,並提供全域存取點。
網路遊戲服務端需承載大量玩家,參考 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();
}
static void EnterPlayer(object playerName)
{
LoadBalanceServer lbs = LoadBalanceServer.GetLoadBalanceServer();
lbs.GetLobbyServer().EnterPlayer(playerName.ToString());
}
}
class LoadBalanceServer
{
private const int SERVER_COUNT = 3;
private List<LobbyServer> _servers = new List<LobbyServer>();
private static volatile LoadBalanceServer _instance;
private static readonly object _lock = new object();
private LoadBalanceServer()
{
for (int i = 0; i < SERVER_COUNT; i++)
_servers.Add(new LobbyServer("LobbyServer" + i));
}
public static LoadBalanceServer GetLoadBalanceServer()
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
Thread.Sleep(100); // 模擬建構延遲
_instance = new LoadBalanceServer();
}
}
}
return _instance;
}
public LobbyServer GetLobbyServer()
{
LobbyServer least = _servers[0];
for (int i = 1; i < SERVER_COUNT; i++)
if (_servers[i].PlayerList.Count < least.PlayerList.Count)
least = _servers[i];
return least;
}
public void ShowServerInfo()
{
foreach (var ls in _servers)
{
Console.WriteLine("=================" + ls.ServerName + "=================");
foreach (var player in ls.PlayerList)
Console.WriteLine(player);
}
}
}
class LobbyServer
{
private List<string> _players = new List<string>();
public List<string> PlayerList => _players;
public string ServerName { get; }
public LobbyServer(string name) => ServerName = name;
public void EnterPlayer(string playerName) => _players.Add(playerName);
}
}
volatile 關鍵字防止指令重排序