ASP.NET温故而知新学习系列之ASP.NET多线程编程—.NET下的多线程编程临界区(八)
阅读目录
一:临界区概述
二:临界区操作
三:实例
四:通过Interlocked类设置临界区
五:通过Monitor类设置临界区
一:临界区概述
在某个时间段内可以有两个线程同时执行,那么两个线程访问的要都是同一个数据的话,那么这种情况下会出现一些不必要的事情,比如:我的银行账户总额有5000,某天我拿着存折去柜台取4000准备交物业费,媳妇拿着银行卡去取2000给孩子交学费,当某一个时间点上,我俩同时取钱,那么首先银行是这样操作的,先判断账户余额大于我要取的4000,好了给我吐出来4000大洋,因为是同时进行,媳妇那边也是先判断账户余额大于她要取的2000,好了给她吐出来2000大洋,这样的话我们账户总额只有5000元,我和我老婆却一共取出来了6000元,那么多吐出来的这1000银行只能认了,银行的账户余额为-1000,我们是不希望这种情况发生的,那么我们应该怎么做呢?应该是这样来操作的,首先当我取4000的时候,被锁住也就是我们经常说的加锁,同一个时间点上媳妇取2000的时候,取不了,等我取完了,锁被释放了,媳妇才能取,媳妇取2000的时候系统会提示余额剩下1000了,不能提取2000,那么这里临界区指的就是操作这个数据的区域
二:临界区操作
. Lock关键字将某个语句块标记为临界区,另一个线程不能进入临界区
. Interlocked类为多个线程共享的变量提供原子操作
. Monitor类提供同步对对象的访问机制,Monitor类通过向单个对象设置对象锁来控制对对象的访问,使用Enter和Exit来标记临界区的开头和结尾
三:实例
当我们取消Lock关键字的时候,报异常了如图一,是因为 _money为负数了,也就是账户现有金额为负数了,银行的钱为负数了,我们不取消Lock关键字如图二程序运行正常,为什么会这样呢?红色代码和黄色代码部分为原子操作,当有线程在访问红色代码部分的时候,因为是并行执行,另外的线程也进来了减钱了,如果没有lock关键字的存在,那么两个线程都能执行到黄色代码部分,比如说this._money被减少到等于500的时候,因为intAmount一直都是500,那么if(this._money >= intAmount)是成立的,那么这两个线程都能进到if的语句块里面做黄色代码部分了也就是this._money = this._money - intAmount,第一个线程0=500-500,第二个线程-500=0-500,连着减两次,所以最后this._money为负数了,所以我们要加lock关键字在一个时间点上只能一个线程进来
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace CriticalZone
{
public class Money
{
public int _money;//账户现有金额
/// <summary>
/// 初始化账户总额www.zzzyk.com
/// </summary>
/// <param name="intTotalMoney">账户总额</param>
public Money(int intTotalMoney)
{
this._money = intTotalMoney;
}
/// <summary>
/// 判断银行剩下的钱是不是负数,如果是负数则抛出异常,如果不是负数则继续取钱
/// </summary>
/// <param name="intAmount">要取走的金额</param>
/// <returns></returns>
public int Withdraw(int intAmount)
{
if (this._money < 0)
{
throw new Exception("银行的钱为负数了");
}
return UseLock(intAmount);
}
public int UseLock(int intAmount)
{
//可以注释lock看看效果
lock (this)
{
//如果银行的钱大于等于要取走的金额,则减少钱
if (this._money >= intAmount)
{
Thread.Sleep(5);
this._money = this._money - intAmount;
return intAmount;
}
else
{
return 0;
}
}
}
/// <summary>
/// 取钱动作
/// </summary>
public void GetMoney()
{
//连着取100次500元现金,那么就目前来说,账户总额为5000元,只能取十次就不能取了,账户为0了,金额就不应该在减少了
for (int i = 0; i < 100; i++)
{
Withdraw(500);
}
}
}
class Program
{
//声明十个线程,相当于十个人同时去取钱
static Thread[] threads = new Thread[10];
static void Main(string[] args)
{
Money money = new Money(5000);
//创建十个线程,这十个线程做同样一件事情GetMoney取钱
for(int i = 0;i < 10;i++)
{
补充:Web开发 , ASP.Net ,