我们都知道,lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。也就是,说在多线程中,使用lock关键字,可以让被lock的对象,一次只被一个线程使用。
lock语句根本使用的就是Monitor.Enter和Monitor.Exit,也就是说lock(this)时执行Monitor.Enter(this),大括号结束时执行Monitor.Exit(this). 也就是说,Lock关键字,就是一个语法糖而已。
使用lock需要注意的地方:
1.lock不能锁定空值某一对象可以指向Null,但Null是不需要被释放的。(请参考:认识全面的null)
2.lock不能锁定string类型,虽然它也是引用类型的。因为字符串类型被CLR“暂留”
3.lock锁定的对象是一个程序块的内存边界
4.值类型不能被lock,因为前文标红字的“对象被释放”,值类型不是引用类型的
5.lock就避免锁定public 类型或不受程序控制的对象。
实例:
我们先看下加上lock和不加lock同一个程序有什么不同。
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LockDemo
{
class Program
{
private static Student s1 = new Student() { name = "Tim", age = 8 };
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Task.Run(() => UpdateAge());
}
Console.ReadLine();
}
private static void UpdateAge()
{
lock (s1)
{
s1.age--;
if (s1.age > 0)
Console.WriteLine($"s1.name:{s1.name}, s1.age: {s1.age}");
}
}
}
public class Student
{
public int age { get; set; }
public string name { get; set; }
}
}
所以在使用多线程的同时,这个时候使用lock就会对使用多线程的效率产生影响。之所以会有lock的产生,是由于对于公共的变量,为了避免多线程处理造成非预期的影响,对该对象进行上锁处理,确保该对象是我想要的那一个。
例如上述代码中的UpdateAge函数,输出的Console.WriteLine里面的是
就未必是s1.age--的s1,而可能是由于多线程,再次调用了UpdateAge()函数,此时刚好执行了s1.age--, 所以第一次的Console.WriteLine($"s1.name:{s1.name}, s1.age: {s1.age}"); 里面的age就存在很大的不确定性。
参考地址:https://www.cnblogs.com/ldyblogs/p/lock.html
https://www.cnblogs.com/lgxlsm/p/4834755.html