มันเป็นรูปแบบที่ไม่ดีที่จะใช้this
ในข้อความสั่งการล็อกเนื่องจากโดยทั่วไปจะอยู่นอกเหนือการควบคุมของคุณซึ่งอาจมีคนอื่นล็อกอยู่บนวัตถุนั้น
เพื่อวางแผนการทำงานแบบขนานอย่างเหมาะสมควรใช้ความระมัดระวังเป็นพิเศษในการพิจารณาสถานการณ์การหยุดชะงักที่เป็นไปได้และการมีจุดเข้าล็อคจำนวนหนึ่ง ตัวอย่างเช่นผู้ใดก็ตามที่มีการอ้างอิงถึงวัตถุสามารถล็อคมันได้โดยไม่ต้องมีผู้ออกแบบ / ผู้สร้างวัตถุที่รู้เกี่ยวกับมัน สิ่งนี้จะเพิ่มความซับซ้อนของการแก้ปัญหาแบบมัลติเธรดและอาจส่งผลกระทบต่อความถูกต้อง
ฟิลด์ส่วนตัวมักจะเป็นตัวเลือกที่ดีกว่าเนื่องจากคอมไพเลอร์จะบังคับใช้ข้อ จำกัด การเข้าถึงและจะห่อหุ้มกลไกการล็อก การใช้การthis
ละเมิด encapsulation โดยเปิดเผยส่วนหนึ่งของการดำเนินการล็อคของคุณต่อสาธารณะ ยังไม่ชัดเจนว่าคุณจะได้รับการล็อคthis
เว้นแต่จะได้รับการบันทึกไว้ แม้กระนั้นก็ตามการใช้เอกสารประกอบเพื่อป้องกันปัญหานั้นไม่เหมาะสม
ในที่สุดก็มีความเข้าใจผิดที่lock(this)
เกิดขึ้นจริงที่ปรับเปลี่ยนวัตถุที่ส่งผ่านเป็นพารามิเตอร์และในทางใดทางหนึ่งทำให้อ่านอย่างเดียวหรือไม่สามารถเข้าถึงได้ นี้เป็นเท็จ วัตถุผ่านเป็นพารามิเตอร์เพื่อlock
ทำหน้าที่เป็นกุญแจเท่านั้น หากล็อคอยู่ในคีย์นั้นจะไม่สามารถล็อคได้ มิฉะนั้นอนุญาตให้ล็อคได้
นี่คือเหตุผลที่ไม่ดีที่จะใช้สตริงเป็นคีย์ในlock
คำสั่งเนื่องจากมันไม่เปลี่ยนรูปและใช้ร่วมกัน / สามารถเข้าถึงได้ทั่วทุกส่วนของแอปพลิเคชัน คุณควรใช้ตัวแปรส่วนตัวแทนObject
อินสแตนซ์จะทำงานได้ดี
เรียกใช้รหัส C # ต่อไปนี้เป็นตัวอย่าง
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public void LockThis()
{
lock (this)
{
System.Threading.Thread.Sleep(10000);
}
}
}
class Program
{
static void Main(string[] args)
{
var nancy = new Person {Name = "Nancy Drew", Age = 15};
var a = new Thread(nancy.LockThis);
a.Start();
var b = new Thread(Timewarp);
b.Start(nancy);
Thread.Sleep(10);
var anotherNancy = new Person { Name = "Nancy Drew", Age = 50 };
var c = new Thread(NameChange);
c.Start(anotherNancy);
a.Join();
Console.ReadLine();
}
static void Timewarp(object subject)
{
var person = subject as Person;
if (person == null) throw new ArgumentNullException("subject");
// A lock does not make the object read-only.
lock (person.Name)
{
while (person.Age <= 23)
{
// There will be a lock on 'person' due to the LockThis method running in another thread
if (Monitor.TryEnter(person, 10) == false)
{
Console.WriteLine("'this' person is locked!");
}
else Monitor.Exit(person);
person.Age++;
if(person.Age == 18)
{
// Changing the 'person.Name' value doesn't change the lock...
person.Name = "Nancy Smith";
}
Console.WriteLine("{0} is {1} years old.", person.Name, person.Age);
}
}
}
static void NameChange(object subject)
{
var person = subject as Person;
if (person == null) throw new ArgumentNullException("subject");
// You should avoid locking on strings, since they are immutable.
if (Monitor.TryEnter(person.Name, 30) == false)
{
Console.WriteLine("Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string \"Nancy Drew\".");
}
else Monitor.Exit(person.Name);
if (Monitor.TryEnter("Nancy Drew", 30) == false)
{
Console.WriteLine("Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!");
}
else Monitor.Exit("Nancy Drew");
if (Monitor.TryEnter(person.Name, 10000))
{
string oldName = person.Name;
person.Name = "Nancy Callahan";
Console.WriteLine("Name changed from '{0}' to '{1}'.", oldName, person.Name);
}
else Monitor.Exit(person.Name);
}
}
เอาต์พุตคอนโซล
'this' person is locked!
Nancy Drew is 16 years old.
'this' person is locked!
Nancy Drew is 17 years old.
Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string "Nancy Drew".
'this' person is locked!
Nancy Smith is 18 years old.
'this' person is locked!
Nancy Smith is 19 years old.
'this' person is locked!
Nancy Smith is 20 years old.
Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!
'this' person is locked!
Nancy Smith is 21 years old.
'this' person is locked!
Nancy Smith is 22 years old.
'this' person is locked!
Nancy Smith is 23 years old.
'this' person is locked!
Nancy Smith is 24 years old.
Name changed from 'Nancy Drew' to 'Nancy Callahan'.