我们在程序开发中,经常会出现多线程中进行同步操作,比如多人抢票,多人抢红包,库存数量的更新,都需要进行局部同步操作。
使用锁对象进行同步访问的几种代码示例进行比较:
1.静态类的静态变量锁,加锁有效
2.局部类成员变量锁,加锁无效【非常严重】!
3.公共类成员变量锁,加锁有效
4.局部类静态变量锁,加锁有效
5.公共类静态变量锁,加锁有效
防止出错的解决方案:
多线程同时调用一个同步方法【需要排队执行的方法】时,为了防止出现不小心出现的【加锁无效】,请将加锁变量设置为静态的【static】
新建.net 4.6.1控制台应用程序【C#】,
新建类GlobalUtil.cs
GlobalUtil类源代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AboutLockDemo
{
/// <summary>
/// 公共共享变量 与 加锁、释放锁方法
/// </summary>
public class GlobalUtil
{
/// <summary>
/// 共享变量的值
/// </summary>
public static int SharedVariable = 0;
/// <summary>
/// 复位共享变量的值
/// </summary>
public static void ResetSharedVariable()
{
SharedVariable = 0;
}
/// <summary>
/// 添加锁,进入锁
/// </summary>
/// <param name="lockedValue"></param>
public static void EnterLock(ref int lockedValue)
{
bool isWriteLog = false;
while (Interlocked.Exchange(ref lockedValue, 1) != 0)
{
if (!isWriteLog)
{
isWriteLog = true;
Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}】触发多线程同时调用接口");
}
}
Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}】开始执行同步方法,已添加锁...");
}
/// <summary>
/// 释放锁,解除锁
/// </summary>
/// <param name="lockedValue"></param>
public static void ReleaseLock(ref int lockedValue)
{
Interlocked.Exchange(ref lockedValue, 0);//释放锁
Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}】结束执行同步方法,已释放锁...");
}
}
}
新建静态类LockedStaticForStaticClass.cs
LockedStaticForStaticClass类源代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AboutLockDemo
{
/// <summary>
/// 静态类中使用静态变量锁
/// </summary>
public static class LockedStaticForStaticClass
{
/// <summary>
/// 加锁变量
/// </summary>
private static int lockedValue = 0;
/// <summary>
/// 加锁方法
/// </summary>
public static void LockedMethod()
{
GlobalUtil.EnterLock(ref lockedValue);
GlobalUtil.SharedVariable++;
Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(100, 500));
Console.WriteLine($"【加一】以后当前共享变量的值【{GlobalUtil.SharedVariable}】");
GlobalUtil.ReleaseLock(ref lockedValue);
}
}
}
新建实例化成员变量类LockedMemberForInstanceClass.cs
LockedMemberForInstanceClass源程序如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AboutLockDemo
{
/// <summary>
/// 实例化类中使用成员变量锁
/// </summary>
public class LockedMemberForInstanceClass
{
/// <summary>
/// 加锁变量
/// </summary>
private int lockedValue = 0;
/// <summary>
/// 加锁方法
/// </summary>
public void LockedMethod()
{
GlobalUtil.EnterLock(ref lockedValue);
GlobalUtil.SharedVariable++;
Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(100, 500));
Console.WriteLine($"【加一】以后当前共享变量的值【{GlobalUtil.SharedVariable}】");
GlobalUtil.ReleaseLock(ref lockedValue);
}
}
}
新建实例化静态成员类LockedStaticForInstanceClass.cs
LockedStaticForInstanceClass源程序如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AboutLockDemo
{
/// <summary>
/// 实例化类中使用静态对变量锁
/// </summary>
public class LockedStaticForInstanceClass
{
/// <summary>
/// 加锁变量
/// </summary>
private static int lockedValue = 0;
/// <summary>
/// 加锁方法
/// </summary>
public void LockedMethod()
{
GlobalUtil.EnterLock(ref lockedValue);
GlobalUtil.SharedVariable++;
Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(100, 500));
Console.WriteLine($"【加一】以后当前共享变量的值【{GlobalUtil.SharedVariable}】");
GlobalUtil.ReleaseLock(ref lockedValue);
}
}
}
在默认的Program.cs中输入测试代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AboutLockDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--------------测试几种锁的程序写法以及具体的处理结果--------------");
TestStaticClassLock();
TestInstanceLocalClassLock();
TestInstanceCommonClassLock();
TestInstanceLocalClassStaticLock();
TestInstanceCommonClassStaticLock();
Console.WriteLine("多线程同时调用一个同步方法【需要排队执行的方法】时,为了防止出现不小心出现的【加锁无效】,请将加锁变量设置为静态的【static】,形如:");
Console.WriteLine(" private static int lockedValue = 0;");
Console.ReadLine();
}
/// <summary>
/// 静态类变量,加锁有效
/// </summary>
static void TestStaticClassLock()
{
GlobalUtil.ResetSharedVariable();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
int taskIndex = i;
tasks.Add(Task.Run(() =>
{
Console.WriteLine($"开始执行线程【{taskIndex + 1}】...");
LockedStaticForStaticClass.LockedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("--------------静态类的静态变量锁,加锁有效--------------");
}
/// <summary>
/// 局部类成员变量锁,导致的结果是加锁无效【无法加锁的代码】
/// </summary>
static void TestInstanceLocalClassLock()
{
GlobalUtil.ResetSharedVariable();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
int taskIndex = i;
tasks.Add(Task.Run(() =>
{
Console.WriteLine($"开始执行线程【{taskIndex + 1}】...");
//局部变量
LockedMemberForInstanceClass instanceObject = new LockedMemberForInstanceClass();
instanceObject.LockedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("--------------局部类成员变量锁,加锁无效【非常严重】!--------------");
}
/// <summary>
/// 公共类成员变量锁,加锁有效
/// </summary>
static void TestInstanceCommonClassLock()
{
GlobalUtil.ResetSharedVariable();
//公共变量
LockedMemberForInstanceClass instanceObject = new LockedMemberForInstanceClass();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
int taskIndex = i;
tasks.Add(Task.Run(() =>
{
Console.WriteLine($"开始执行线程【{taskIndex + 1}】...");
instanceObject.LockedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("--------------公共类成员变量锁,加锁有效--------------");
}
/// <summary>
/// 局部类静态变量锁,加锁有效
/// </summary>
static void TestInstanceLocalClassStaticLock()
{
GlobalUtil.ResetSharedVariable();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
int taskIndex = i;
tasks.Add(Task.Run(() =>
{
Console.WriteLine($"开始执行线程【{taskIndex + 1}】...");
//局部变量
LockedStaticForInstanceClass instanceObject = new LockedStaticForInstanceClass();
instanceObject.LockedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("--------------局部类静态变量锁,加锁有效--------------");
}
/// <summary>
/// 公共类静态变量锁,加锁有效
/// </summary>
static void TestInstanceCommonClassStaticLock()
{
GlobalUtil.ResetSharedVariable();
//公共类变量
LockedStaticForInstanceClass instanceObject = new LockedStaticForInstanceClass();
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
int taskIndex = i;
tasks.Add(Task.Run(() =>
{
Console.WriteLine($"开始执行线程【{taskIndex + 1}】...");
instanceObject.LockedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("--------------公共类静态变量锁,加锁有效--------------");
}
}
}
程序运行如图: