环境:
net4.5
vs2022
目录
模拟商品抢购,单个服务器,可以通过本地服务器缓存或数据库锁就可以处理,
分布式服务器的话,想要实现进程与进程之间实现同步锁,可以使用redis、数据库锁、ZooKeeper来实现。
单体服务器:
可以通过HttpRuntime.Cache缓存来简单实现
public class RuntimeCacheLock
{
private static System.Web.Caching.Cache cache = HttpRuntime.Cache;
private static readonly object lockObj = new object();
public bool GetLock(string lockKey, object value, int lockExpirySeconds = 10, double waitLockSeconds = 0)
{
DateTime begin = DateTime.Now;
while (true)
{
lock (lockObj)
{
//循环获取取锁
if (object.ReferenceEquals(cache.Get(lockKey), null))
{
//设置锁的过期时间
cache.Add(lockKey, value, null, DateTime.UtcNow.AddSeconds(lockExpirySeconds),
System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
return true;
}
}
//不等待锁则返回
if (waitLockSeconds == 0) break;
//超过等待时间,则不再等待
if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds) break;
}
return false;
}
public object GetLockValue(string lockKey)
{
object obj = cache.Get(lockKey);
if (obj != null)
{
return obj;
}
return null;
}
public void ReleaseLock(string key)
{
cache.Remove(key);
}
}
}
program:
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"主线程{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 50; i++)
{
ThreadPool.QueueUserWorkItem((t) =>
{
Show();
});
}
Console.ReadKey();
}
private static int value = 30;
private static void Show()
{
string key = nameof(Show);
string guid = Guid.NewGuid().ToString();
RuntimeCacheLock runtimeCacheLock = new RuntimeCacheLock();
try
{
if (runtimeCacheLock.GetLock(key, guid, 5, 10))
{
value--;
Thread.Sleep(1000);//模拟业务操作
if (value <= 0)
{
Console.WriteLine($"商品已经无货");
return;
}
else
{
Console.WriteLine($"value={value}");
return;
}
}
else
{
Console.WriteLine("稍后重试");
return;
}
}
finally
{
if (runtimeCacheLock.GetLockValue(key) != null && guid.Equals(runtimeCacheLock.GetLockValue(key)))
runtimeCacheLock.ReleaseLock(key);
}
}
}
分布式负载服务器:
1、Redis:
单节点
引用CSRedisCore库,版本3.6.8.0
public class RedisLock
{
public RedisLock()
{
var csredis = new CSRedis.CSRedisClient("127.0.0.1:6379");
RedisHelper.Initialization(csredis);//初始化
}
public bool GetLock(string lockKey, object value, int lockExpirySeconds = 10, double waitLockSeconds = 0)
{
DateTime begin = DateTime.Now;
while (true)
{
if (RedisHelper.SetNx(lockKey, value))//key值不存在时,设置缓存
{
RedisHelper.Expire(lockKey, lockExpirySeconds);
return true;
}
//不等待锁则返回
if (waitLockSeconds == 0) break;
//超过等待时间,则不再等待
if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds) break;
}
return false;
}
public object GetLockValue(string lockKey)
{
string obj = RedisHelper.Get(lockKey);
if (obj != null)
{
return obj;
}
return null;
}
public void ReleaseLock(string key)
{
RedisHelper.Del(key);
}
}
program:
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"主线程{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 50; i++)
{
ThreadPool.QueueUserWorkItem((t) =>
{
RedisShow();
});
}
Console.ReadKey();
}
private static int value = 30;
private static void RedisShow()
{
string key = nameof(RedisShow);
string guid = Guid.NewGuid().ToString();
RedisLock @lock= new RedisLock();
try
{
if (@lock.GetLock(key, guid, 5, 10))
{
value--;
Thread.Sleep(1000);
if (value <= 0)
{
Console.WriteLine($"商品已经无货");
return;
}
else
{
Console.WriteLine($"value={value}");
return;
}
}
else
{
Console.WriteLine("稍后重试");
return;
}
}
finally
{
if (@lock.GetLockValue(key) != null && guid.Equals(@lock.GetLockValue(key)))
@lock.ReleaseLock(key);
}
}
}
2、RedLock:
多个单节点redis组成
引用RedLockNet库,版本2.1.0.0
internal class RedLock
{
private static RedLockFactory _redlockFactory;
static RedLock()
{
var endPoints = new List<RedLockEndPoint>
{
new DnsEndPoint("localhost", 6379),
//new DnsEndPoint("redis2", 6379),
//new DnsEndPoint("redis3", 6379)
};
_redlockFactory = RedLockFactory.Create(endPoints);
}
private IRedLock _redLock;
public bool GetLock(string lockKey, object value, int lockExpirySeconds = 10, double waitLockSeconds = 10)
{
var expiry = TimeSpan.FromSeconds(lockExpirySeconds);//过期时间
var wait = TimeSpan.FromSeconds(waitLockSeconds);//等待时间
var retry = TimeSpan.FromSeconds(2);//重试时间
_redLock = _redlockFactory.CreateLock(lockKey, expiry, wait, retry);
//确保获取到锁
if (_redLock.IsAcquired)
{
return true;
}
return false;
}
public object GetLockValue(string lockKey)
{
return string.Empty;
}
public void ReleaseLock(string lockKey)
{
if (_redLock != null)
_redLock.Dispose();
//if (_redlockFactory != null)
// _redlockFactory.Dispose();
}
}
program:
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"主线程{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 50; i++)
{
RedLock @lock = new RedLock();
ThreadPool.QueueUserWorkItem((t) =>
{
RedLockShow(@lock);
});
}
Console.ReadKey();
}
private static int value = 30;
private static void RedLockShow(RedLock @lock)
{
string key = nameof(RedLockShow);
string guid = Guid.NewGuid().ToString();
try
{
if (@lock.GetLock(key, guid, 10, 20))
{
value--;
Thread.Sleep(1000);
if (value <= 0)
{
Console.WriteLine($"商品已经无货");
return;
}
else
{
Console.WriteLine($"value={value}");
return;
}
}
else
{
Console.WriteLine("稍后重试");
return;
}
}
finally
{
@lock.ReleaseLock(key);
}
}
}