• lock语句

lock 语句获取给定对象的互斥 lock,执行语句块,然后释放 lock。 持有 lock 时,持有 lock 的线程可以再次获取并释放 lock。 阻止任何其他线程获取 lock 并等待释放 lock。

  • 为什么需要锁

作为C#的程序员来说,在遇到线程同步的需求时最常用的就是lock关键字。lock 的目的很明确,就是不想让别人使用这段代码,体现在多线程情况下,只允许当前线程执行该代码区域,其他线程等待直到该线程执行结束;这样可以多线程避免同时使用某一方法造成数据混乱。

  • lock的等效代码

在.NET的多线程程序中,经常会遇到lock关键字来控制同步,比如下列代码:

private object o = new object();

public void Work()

{

  lock(o)

  {

    //做一些需要线程同步的工作

  }

}

事实上,lock这个关键字是C#为方便程序员而定义的语法,它等效于安全地使用System.Threading.Monitor类型。上面的代码就直接等效于下面的代码:

private object o = new object();

public void Work()

{

  //这里很重要,是为了避免直接使用私有成员o,而导致线程不安全

  object temp = o;

  System.Threading.Monitor.Enter(temp);

  try

  {

    //做一些需要线程同步的工作

  }

  finally

  {

    System.Threading.Monitor.Exit(temp);

  }

}

正如你看到的,真正实现了线程同步功能的,就是System.Threading.Monitor类型,lock关键字只是用来代替调用Enter、Exit方法,并且将所有的工作包含在try块内,以保证其最终退出同步。

注意:我们lock的一般是对象,不是值类型和字符串。

1、为什么不能lock值类型

比如lock(1)呢?lock本质上Monitor.Enter,Monitor.Enter会使值类型装箱,每次lock的是装箱后的对象。lock 其实是类似编译器的语法糖,因此编译器直接限制住不能lock值类型。退一万步说,就算能编译器允许你lock(1),但是 object.ReferenceEquals(1,1)始终返回false(因为每次装箱后都是不同对象),也就是说每次都会判断成未申请互斥锁,这样 在同一时间,别的线程照样能够访问里面的代码,达不到同步的效果。同理lock((object)1)也不行。

2、Lock字符串

那么lock("xxx")字符串呢?MSDN上的原话是:

锁定字符串尤其危险,因为字符串被公共语言运行库 (CLR)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何 位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。

3、MSDN推荐的Lock对象

通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于 对象)也可能导致问题。

而且lock(this)只对当前对象有效,如果多个对象之间就达不到同步的效果。

而自定义类推荐用私有的只读静态对象,比如:

private static readonly object obj = new object();

为什么要设置成只读的呢?这是因为如果在lock代码段中改变obj的值,其它线程就畅通无阻了,因为互斥锁的对象变了,object.ReferenceEquals必然返回false。

  • Lock 关键字锁定静态变量和非静态变量的区别

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace testLock
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("----------开始测试单实例非静态锁----------"); MyLock myLock = new MyLock();
for (int i = ; i < ; i++)
{
Thread t = new Thread(myLock.Increment1);
t.Start();
} Thread.Sleep( * ); Console.WriteLine("----------开始测试单实例静态锁----------"); MyLock myLock2 = new MyLock();
for (int i = ; i < ; i++)
{
Thread t = new Thread(myLock2.Increment2);
t.Start();
} Thread.Sleep( * ); Console.WriteLine("----------开始测试多实例非静态锁----------"); for (int i = ; i < ; i++)
{
MyLock mlock = new MyLock();
Thread t = new Thread(mlock.Increment1);
t.Start();
} Thread.Sleep( * ); Console.WriteLine("----------开始测试多实例静态锁----------"); for (int i = ; i < ; i++)
{
MyLock mlock = new MyLock();
Thread t = new Thread(mlock.Increment2);
t.Start();
} Console.Read(); }
} public class MyLock
{
//静态变量锁对象
private readonly static object staticObj = new object(); //非静态变量锁对象
private readonly object obj = new object(); //成员变量
private static int i1 = ;
private static int i2 = ; /// <summary>
/// 非静态锁
/// </summary>
/// <param name="handleObject">要处理的对象</param>
public void Increment1(object handleObject)
{
lock (obj)
{ Console.WriteLine("i1的值为:{0}", i1); //这里刻意制造线程并行机会,来检查同步的功能 Thread.Sleep(); i1++; Console.WriteLine("i1自增后为:{0}", i1); }
} /// <summary>
/// 静态锁
/// </summary>
/// <param name="handleObject">要处理的对象</param>
public void Increment2(object handleObject)
{
lock (staticObj)
{ Console.WriteLine("i2的值为:{0}", i2); //这里刻意制造线程并行机会,来检查同步的功能 Thread.Sleep(); i2++; Console.WriteLine("i2自增后为:{0}", i2); }
} }
}

单实例非静态锁,线程没有并发(加锁成功);

单实例静态锁,线程没有并发(加锁成功);

多实例非静态锁,线程并发(加锁失败);

多实例静态锁,线程没有并发(加锁成功)

说明:以上内容是根据网上内容进行整理,并加以归纳。

c# lock 锁的更多相关文章

  1. Lock锁的使用示例

    Lock锁是java5用来代替synchronized的一种面向对象的锁的方案 public class LockDemo { /** * Lock是用来替换synchronized, 优点是Lock ...

  2. Android(java)学习笔记69:JDK5之后的Lock锁的概述和使用

    1. Lock锁的概述: java.util.concurrent.locks,接口Lock 首先Lock是一个接口,Lock实现提供了比使用synchronized方法 和 同步代码块更为广泛的锁定 ...

  3. python多线程threading.Lock锁用法实例

    本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...

  4. Lock锁_线程_线程域

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  5. (删)Java线程同步实现二:Lock锁和Condition

    在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...

  6. 转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)

    简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接 ...

  7. 使用Lock锁生产者消费者模式

    package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...

  8. JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

    JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...

  9. java并发编程的艺术——第五章总结(Lock锁与队列同步器)

    Lock锁 锁是用来控制多个线程访问共享资源的方式. 一般来说一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程访问共享资源,如读写锁). 在Lock接口出现前,java使用synchr ...

  10. Java中的Lock锁

    Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...

随机推荐

  1. C语言程序设计100例之(13):最大子段和

    例13        最大子段和 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大.例如在序列2,-4,3,-1,2,-4,3中,最大的子段和为4,该子段为3,-1,2. 输入格式 第一 ...

  2. PHPer的项目RESTful API设计规范是怎样的?

    RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计. 什么是RESTful RESTful是一种软件设计风格, 主要用于客户端与服务端交互的软件. 一般来说RESTful ...

  3. SpringBoot系列之配置文件占位符使用

    SpringBoot系列之配置文件占位符使用 Springboot占位符支持的有随机数和配置的值等等,本博客主要介绍的是随机数和获取属性配置值的简单用法 随机数获取 支持的写法有: ${random. ...

  4. CentOS 7 firewalld详解,添加删除策略

    一.CentOS7中firewall防火墙 修改防火墙配置文件之前,需要对之前防火墙[/etc/firewalld/zones/public.xml]做好备份 重启防火墙后,需要确认防火墙状态和防火墙 ...

  5. 关于wordpress其他分类页面正常单一分类页面白屏的解决

    关于wordpress其他分类页面正常单一分类页面白屏的解决 朋友的一个站,10个分类页面,9个正常,其中一个打开白屏或者500错误 下载 nginx的日志文件查看 收到如下提示: ecv() fai ...

  6. Fiddler 插件开发,使用 WPF 作为 UI 控件

    Fiddler 插件的 UI,本身使用的 WinForm,这个例子是使用 WinForm 中的 WPF 容器,将 WPF 控件作为 Fiddler 插件的 UI 使用. 为什么使用 WPF ?为了自适 ...

  7. HTTP 压测工具wrk简介

    前段时间项目压测,看到开发命令行下使用这个命令进行压测非常简洁.方便,萌发了学习的兴趣,这里仅做简单介绍. 安装 wrk支持大多数UNIX系统,不支持Windows.需要操作系统支持LuaJIT和Op ...

  8. 跳转常规 -- 为什么不要使用404、500等http状态码作为业务代码响应

    不要使用HTTP状态码作为业务代码响应 HTTP状态码 是指浏览器访问网址,成功或异常时浏览器或服务器告知用户的代码数字,它指的是网络或服务器的状态,有着不同的含义. 参加MDN.Java Api,常 ...

  9. 从HTML开始

    <html>:做网页,是一种超文本标记语言. 超文本:既有添加文本的能力,还可以添加图片,视频等多媒体元素. 标记:由标签组成.不同的标签有不同的效果.        开始标签,结束标签. ...

  10. Android apk签名方法介绍

    还望支持个人博客站:http://www.enjoytoday.cn 参考博客:http://www.enjoytoday.cn/posts/203 为什么要签名 在介绍签名方法之前,首先我们来了解下 ...