由单例模式学到:lock锁
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
lock (xxx)
{
// Critical code section.
}
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
用实例说话:
例1
新建多个线程,用多个线程的操作来模拟实现lock的场景
public static void fun()
{
Thread[] threads = new Thread[500];
User u = new User();
for (int i = 0; i < 50; i++)
{
threads[i] = new Thread(new ParameterizedThreadStart(getInstance));
threads[i].IsBackground = true;
threads[i].Start(u);
}
}
以上新建了50个线程,并且让每个线程都执行getInstance方法,并且每个getInstance方法的参数为User的实例upublic static void getInstance(object obj)
{
User u = (User)obj;
Console.WriteLine(u.addtion());
}以上代码段执行User类的addtion方法,并得到返回值。即:此时有50个线程在执行同一个User实例的u的addtion方法,在执行addtion方法的时候,addtion方法中的lock(this)起到锁的作用,当第一个线程进入lock代码块中后,将会把其他的线程阻塞到外面,直到第一个线程执行完,锁得到释放,其他线程中的一个才得以执行。
public class User
{private static int sin;
public string addtion()
{
lock (this)
{
sin = sin + 10;
Thread.Sleep(50);
return sin.ToString();
}
}
}
如上的代码,如果lock(this)起到锁的作用的话,线程一个一个执行,每个线程的执行sin的值都会增加10。期望的效果为:10,20,30,40,50....
=====执行的效果为
:注意上述代码中的红色字体标记的部分,多个线程执行的都是同一个User实例的addtion方法,所以lock(this)起到了锁了作用,如果让每个线程都实例化一个User类,再去执行自己实例化的User类的addtion方法,那么lock(this)就起不到作用了!
即:public static void fun()
{
Thread[] threads = new Thread[500];
for (int i = 0; i < 50; i++)
{
threads[i] = new Thread(new ParameterizedThreadStart(getInstance));
threads[i].IsBackground = true;
threads[i].Start(i);
}
}
public static void getInstance(object obj)
{
User u = new User();
Console.WriteLine(u.addtion());
}如果是上述代码的话,则lock就锁不住,lock块中可能有多个线程在执行,即:如果第一个线程把sin设置为10,再第一个线程还没有结束之前,第二个线程会再将sin加10,如此循环,n个线程执行之后,那么第一个线程执行结束后,sin的值就变成了n*10。
执行效果为:实例中还涉及到静态字段,静态字段在IL中标记为BeforeFieldInit,即:静态字段是由程序自动执行,与普通字段不同的是,它仅执行一次,在之后类的实例化时,也不需要再此执行。从而上述代码中sin的字段才得以保存。如果sin字段的static去掉的话,则输出的就是:10,10,10,10....
由此即可得到结论:lock(this) 锁定 当前实例对象,如果有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。
lock中的this表示的是当前实例,对于同一个实例的多线程来说,当第一个现成进来的时,通过lock(this)将当前实例上锁,那么当此实例的其他线程进来的时候,该实例已经上锁,所以就不能进入;而对于每个线程都实例化一个对象就不一样了,当第一个线程进来的时候,lock将第一个线程的实例上锁,那么之后所有的第一个线程实例化的对象就不能再进入访问,这里仅仅是对第一个线程实例化的对象,如果是除此之外的所有其他的对象的话,是起不到锁的作用,即:当第二个线程、第三个线程、、等,到达lock时,是不被锁上的!
例2
既然lock(this)只能防止当前实例多线程访问,不能防止其他实例进入!对于上述的内容如果了解之后,不难想到如何做到绝对防止其他线程(无论是什么实例)进入lock的逻辑块,其实就来实例化一个任意的对象(静态的),例如:private static object obj=new object();lock(obj);因为静态的对象只是由程序自动执行一次,之后再实例化时,用得还是原来的,下面就来说一下访问流程,新建n个任意实例的线程,当第一个线程进来时,利用lock将obj上锁,第一个线程进入lock逻辑块中执行,当第二个、第三个等线程进来时,因为obj是静态的对象,所有obj的值还是第一线程给设置的状态,即:是上锁的。所以其他线程是无法进入的。
public class User
{
private static object obj = new object();
private static int sin = 0;
public string addtion()
{
lock (obj)
{
sin = sin + 10;
Thread.Sleep(500);
return sin.ToString();
}
}
}注意:1.必须是静态字段。不然的话,每次对象的实例化时都会执行一次object obj = new object() ,那么obj每次都是新实例化的对象,其状态肯定是没有上锁的,那样的话就无法起到对任意类型进行锁的操作;2.这里用了objct对象,其实其他对象也是可以的,例如:privatestatic List<User> obj = new List<User>(); 也是可以的,lock的参数其实就是一个变量,当有线程进入的时候,将变量的状态设置为锁,当其他线程到达时,读取到变量的状态如果是锁的,那么就等待,如果不是锁的,那么就进入lock代码块去执行;3.lock的参数其实就是充当变量,当第一个线程到达时候,将其设置为锁状态,当此线程执行完lock代码块中的逻辑后,再将此变量设置成未锁状态!至于上述例子中讨论的不同情况,就是变量如何取值的问题了。
MSDN上说:
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。 常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock")违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
===分析上述的说法:lock(this)出现的问题指的是:lock(this)只对本实例进行锁,其他实例的话就起不到锁的效果,因为lock(this)是将本实例的状态设置为锁,其他实例到达时,this又是值得自己的实例,而不是上次设置为锁的实例,所有就起不到锁的效果了;lock(typeof(MyType))出现的问题是指:他可以对MyType类型的所有实例进行锁的效,果。因为lock(MyType)是将此对象的状态设置为锁,而所有MyType类的实例化都是一个对象MyType,所以他就可以起到对所有实例的锁的效果。虽然其从效果上达到了要求,但是微软现在建议不要使用 lock(typeof(MyType)),因为锁定类型对象是个很缓慢的过程,并且类中的其他线程、甚至在同一个应用程序域中运行的其他程序都可以访问 该类型对象,因此,它们就有可能代替您锁定类型对象,完全阻止您的执行,从而导致你自己的代码的挂起(红色字体表示看不懂);lock("myLock")出现的问题指的是:因为string是引用类型,如果多个变量的值为“myLock”,那么如果lock("myLock")之后,就是将“myLock”的状态设置为锁,那么在栈中的变量名都指向在堆中的“myLock”,即:当前都是锁的状态了,如果其中一个变量名为str1,那么存在lock("myLock")的同时也存在lock(str1),将两个lock设置在两个方法中,并且新建n个线程来执行此两个方法,就会出现当有一个线程执行lock("myLock")之后,lock(str1)的代码块也上锁了。
例:lock("myLock")
static void Main(string[] args)
{
Thread[] threads = new Thread[500];
for (int i = 0; i < 50; i=i+2)
{
threads[i] = new Thread(new ParameterizedThreadStart(fun1));
threads[i+1] = new Thread(new ParameterizedThreadStart(fun2));
threads[i].IsBackground = true;
threads[i+1].IsBackground = true;
threads[i].Start(null);
threads[i+1].Start(null);
}
Console.ReadKey();
}
public static void fun1(object obj)
{
User u = new User();
Console.WriteLine("fun1: "+u.addtion1());
}
public static void fun2(object obj)
{
User u = new User();
Console.WriteLine("fun2:"+u.addtion2());
}public class User
{
private static object obj = new object();
private static string str1 = "123";
private static int sin1 = 0;
private static int sin2 = 1000;
public string addtion1()
{
lock ("123")
{
sin1 = sin1 + 10;
Thread.Sleep(100);
return sin1.ToString() + "-" + DateTime.Now.Ticks.ToString();
}
}
public string addtion2()
{
lock (str1)
{
sin2 = sin2 + 10;
Thread.Sleep(100);
return sin2.ToString() + "-" + DateTime.Now.Ticks.ToString();
}
}
}
打上断点,调试看就可看出。当线程在lock ("123")中执行时,即使到了Thread.Sleep(100);也会等待,然后再继续执行,这就说明此时lock (str1)也是锁的状态!这就是问题所在! public class User
{
private static object obj = new object();
private static string str1 = "12345";
private static int sin1 = 0;
private static int sin2 = 1000;
public string addtion1()
{
lock ("123")
{
sin1 = sin1 + 10;
Thread.Sleep(100);
return sin1.ToString() + "-" + DateTime.Now.Ticks.ToString();
}
}
public string addtion2()
{
lock (str1)
{
sin2 = sin2 + 10;
Thread.Sleep(100);
return sin2.ToString() + "-" + DateTime.Now.Ticks.ToString();
}
}
}
打上断点调试看,当线程在lock ("123")中执行时,当到达Thread.Sleep(100)时,lock (str1)中的代码就会执行,这说明此时lock (str1)的状态是未上锁。实际上两个方法是同时执行的,只不过是因为打上了断电,才造成只能看到一步一步的操作!
由单例模式学到:lock锁的更多相关文章
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- 死锁、Lock锁、等待唤醒机制、线程组、线程池、定时器、单例设计模式_DAY24
1:线程(理解) (1)死锁 概念: 同步中,多个线程使用多把锁之间存在等待的现象. 原因分析: a.线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码, ...
- Java精通并发-Lock锁机制深入详解
从这次开始接触Java1.5推出的并发包中的东东,先看一下jdk中的并发包: 接下来咱们则会集中对这些并发包中的核心进行深入了解,不光要学会怎么用这些并发包中的类,而且还得知道这些功能背后运行的原理, ...
- 第44天学习打卡(JUC 线程和进程 并发和并行 Lock锁 生产者和消费者问题 如何判断锁(8锁问题) 集合类不安全)
什么是JUC 1.java.util工具包 包 分类 业务:普通的线程代码 Thread Runnable 没有返回值.效率相比Callable相对较低 2.线程和进程 进程:一个程序.QQ.exe, ...
- 并发编程系列之Lock锁可重入性与公平性
一.相似之处:Lock锁 vs Synchronized 代码块 Lock锁是一种类似于synchronized 同步代码块的线程同步机制.从Java 5开始java.util.concurrent. ...
- 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锁. 一.同步锁 ...
随机推荐
- 新机上岗 Core i7-4790 @ 3.60GHz 四核 / 16 GB ( 金士顿 DDR3 1866MHz ) / GeForce GTX 970 ( 4 GB / 七彩虹 )
新机上岗 ==============================电脑型号 华硕 All Series 台式电脑操作系统 Windows 7 旗舰版 64位 SP1 ( DirectX 11 ) ...
- [转]如何:定义和处理 SOAP 标头
本文转自:http://msdn.microsoft.com/zh-cn/library/vstudio/8728chd5(v=vs.100).aspx 本主题专门介绍一项旧有技术.现在应通过使用以下 ...
- java的包装类(转)
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数 ...
- 【Fate/kaleid liner 魔法少女☆伊莉雅】系列中实践的、新世代的动画摄影工作流
通常的日本动画的摄影中,是以追加Cell(celluloid 赛璐珞)与背景的合成滤镜处理为主,而在[Fate/kaleid liner 魔法少女☆伊莉雅]系列的,加入了自己使用3DCG软 ...
- 关于Depth Bounds Test (DBT)和在CE3的运用
Depth Bounds Test (DBT) Depth Bounds Test(深度范围检测),是Nvdia GeForce 6系列以后显卡的特性(GPU Programming Guide Ge ...
- JavaScript数据类型(转)
JavaScript中有5种简单数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number和String.还有1种复杂数据类型——Object,Object本质上是由一 ...
- image hover
http://www.nxworld.net/tips/css-image-hover-effects.html
- laravel ajax表格删除
view和jq @extends('layouts.main') @section('content') <h3>User List</h3> <p class=&quo ...
- Linguistic corpora 种子语料库-待分析对象-分析与更新语料库
Computational Linguistics http://matplotlib.org/ https://github.com/matplotlib/matplotlib/blob/maste ...
- 以大写字母“J”来展示位图
'0' => '00011100001111111001100011011000001111000001111000001111000001111000001111000001111000001 ...