要避免这种情况,可以通过使用锁定,帮助防止代码的关键部分出现竞用情况。锁定由 Visual C# 关键字 lock 语句表示,允许执行一个线程来获取对某个对象的独占执行权。下列示例步骤演示了锁定:
1. | 打开 Visual Studio .NET。 |
2. | 在“文件”菜单上,指向“新建”,然后单击“项目”。 |
3. | 单击“项目类型”下的“Visual C# 项目”,然后单击“模板”下的“控制台应用程序”。 |
4. | 在“名称”文本框中,键入 MultiThreadLockApplication,然后单击“确定”。 |
5. | 将 Class1.cs 中的现有代码替换为以下代码: |
using System;
using System.Threading;
namespace MultiThreadLockApplication
{
class Student
{
private static string myTeacherName = "Bill";
private string myName = "Grace";
private static object somePrivateStaticObject = new Object();
public static string TeacherName
{
get
{
string theName;
// Synchronize access to the shared member.
lock(somePrivateStaticObject)
{
Console.WriteLine("Thread {0} starts to get the teacher's name",Thread.CurrentThread.GetHashCode());
theName = myTeacherName;
// Wait for 0.3 second.
Thread.Sleep(300);
Console.WriteLine("Thread {0} finished to get the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), theName);
}
return theName;
}
set
{
lock(somePrivateStaticObject)
{
Console.WriteLine("Thread {0} starts to set the teacher's name.", Thread.CurrentThread.GetHashCode());
myTeacherName = value;
// Wait for 0.3 second.
Thread.Sleep(300);
Console.WriteLine("Thread {0} finished to set the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), value);
}
}
}
public string GetName()
{
string theName;
lock(this)
{
Console.WriteLine("Thread {0} starts to get the student's name.", Thread.CurrentThread.GetHashCode());
theName = myName;
// Wait for 0.3 second.
Thread.Sleep(300);
Console.WriteLine("Thread {0} finished to get the student's name:{1}", Thread.CurrentThread.GetHashCode(), theName);
return theName;
}
}
public string SetName(string NewName)
{
string theOldName;
lock(this)
{
Console.WriteLine("Thread {0} starts to set the student's name.", Thread.CurrentThread.GetHashCode());
theOldName = myName;
myName = NewName;
// Wait for 0.3 second.
Thread.Sleep(300);
Console.WriteLine("Thread {0} finished to set the student's name:{1}", Thread.CurrentThread.GetHashCode(), NewName);
}
return theOldName;
}
}
class Class1
{
public static int WorkItemNum = 20;
public static AutoResetEvent Done = new AutoResetEvent(false);
public static void AccessClassResource(object state)
{
Random rnd = new Random();
string theName;
Student AStudent = (Student) state;
if( (rnd.Next() %2) != 0)
{
if( (rnd.Next() %2) != 0)
{
switch (rnd.Next() %3 )
{
case 0:
Student.TeacherName = "Tom";
break;
case 1:
Student.TeacherName = "Mike";
break;
case 2:
Student.TeacherName = "John";
break;
}
}
else
{
theName = Student.TeacherName;
}
}
else
{
if( (rnd.Next() %2) != 0)
{
switch (rnd.Next() %3 )
{
case 0:
AStudent.SetName("Janet");
break;
case 1:
AStudent.SetName("David");
break;
case 2:
AStudent.SetName("Ben");
break;
}
}
else
{
theName = AStudent.GetName();
}
}
if(Interlocked.Decrement( ref WorkItemNum) == 0)
{
Done.Set();
}
}
[STAThread]
static void Main(string[] args)
{
int threadNum;
Student AStudent = new Student();
// Queue up 20 work items in the ThreadPool.
for (threadNum = 0 ; threadNum <= WorkItemNum -1 ; threadNum++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(AccessClassResource),AStudent);
}
Done.WaitOne();
Console.WriteLine("All operations have completed. Press enter to exit");
Console.ReadLine();
}
}
}