c# lock 锁
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 锁的更多相关文章
- Lock锁的使用示例
Lock锁是java5用来代替synchronized的一种面向对象的锁的方案 public class LockDemo { /** * Lock是用来替换synchronized, 优点是Lock ...
- Android(java)学习笔记69:JDK5之后的Lock锁的概述和使用
1. Lock锁的概述: java.util.concurrent.locks,接口Lock 首先Lock是一个接口,Lock实现提供了比使用synchronized方法 和 同步代码块更为广泛的锁定 ...
- python多线程threading.Lock锁用法实例
本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...
- Lock锁_线程_线程域
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- (删)Java线程同步实现二:Lock锁和Condition
在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...
- 转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接 ...
- 使用Lock锁生产者消费者模式
package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- java并发编程的艺术——第五章总结(Lock锁与队列同步器)
Lock锁 锁是用来控制多个线程访问共享资源的方式. 一般来说一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程访问共享资源,如读写锁). 在Lock接口出现前,java使用synchr ...
- Java中的Lock锁
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
随机推荐
- C语言程序设计100例之(13):最大子段和
例13 最大子段和 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大.例如在序列2,-4,3,-1,2,-4,3中,最大的子段和为4,该子段为3,-1,2. 输入格式 第一 ...
- PHPer的项目RESTful API设计规范是怎样的?
RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计. 什么是RESTful RESTful是一种软件设计风格, 主要用于客户端与服务端交互的软件. 一般来说RESTful ...
- SpringBoot系列之配置文件占位符使用
SpringBoot系列之配置文件占位符使用 Springboot占位符支持的有随机数和配置的值等等,本博客主要介绍的是随机数和获取属性配置值的简单用法 随机数获取 支持的写法有: ${random. ...
- CentOS 7 firewalld详解,添加删除策略
一.CentOS7中firewall防火墙 修改防火墙配置文件之前,需要对之前防火墙[/etc/firewalld/zones/public.xml]做好备份 重启防火墙后,需要确认防火墙状态和防火墙 ...
- 关于wordpress其他分类页面正常单一分类页面白屏的解决
关于wordpress其他分类页面正常单一分类页面白屏的解决 朋友的一个站,10个分类页面,9个正常,其中一个打开白屏或者500错误 下载 nginx的日志文件查看 收到如下提示: ecv() fai ...
- Fiddler 插件开发,使用 WPF 作为 UI 控件
Fiddler 插件的 UI,本身使用的 WinForm,这个例子是使用 WinForm 中的 WPF 容器,将 WPF 控件作为 Fiddler 插件的 UI 使用. 为什么使用 WPF ?为了自适 ...
- HTTP 压测工具wrk简介
前段时间项目压测,看到开发命令行下使用这个命令进行压测非常简洁.方便,萌发了学习的兴趣,这里仅做简单介绍. 安装 wrk支持大多数UNIX系统,不支持Windows.需要操作系统支持LuaJIT和Op ...
- 跳转常规 -- 为什么不要使用404、500等http状态码作为业务代码响应
不要使用HTTP状态码作为业务代码响应 HTTP状态码 是指浏览器访问网址,成功或异常时浏览器或服务器告知用户的代码数字,它指的是网络或服务器的状态,有着不同的含义. 参加MDN.Java Api,常 ...
- 从HTML开始
<html>:做网页,是一种超文本标记语言. 超文本:既有添加文本的能力,还可以添加图片,视频等多媒体元素. 标记:由标签组成.不同的标签有不同的效果. 开始标签,结束标签. ...
- Android apk签名方法介绍
还望支持个人博客站:http://www.enjoytoday.cn 参考博客:http://www.enjoytoday.cn/posts/203 为什么要签名 在介绍签名方法之前,首先我们来了解下 ...