下面是我从百度文库里看到的一段:
下面是一个使用lock关键字的典型例子,我将在注释里向大家说明lock关键字的用法和用途: //lock.cs
using System;
using System.Threading;
internal class Account {
int balance;
Random r = new Random(); internal Account(int initial) {
balance = initial; }
internal int Withdraw(int amount) {
if (balance < 0) {
file://如果balance小于0则抛出异常 throw new Exception("Negative Balance"); }
//下面的代码保证在当前线程修改balance的值完成之前 //不会有其他线程也执行这段代码来修改balance的值 //因此,balance的值是不可能小于0的
lock (this) {
Console.WriteLine("Current Thread:"+Thread.CurrentThread.Name);
file://如果没有lock关键字的保护,那么可能在执行完if的条件判断之后
file://另外一个线程却执行了balance=balance-amount修改了balance的值
file://而这个修改对这个线程是不可见的,所以可能导致这时if的条件已经不成立了
file://但是,这个线程却继续执行balance=balance-amount,所以导致balance可能小于0
if (balance >= amount) {
Thread.Sleep(5);
balance = balance - amount; return amount;
...(http://wenku.baidu.com/view/9510d2649b6648d7c1c746c5.html)
我想知道的是即使这一小段代码即使加了lock,不还是可能在执行完if的条件判断之后,另外一个线程却执行了balance=balance-amount修改了balance的值。这个lock是不是应该放在判断balance之前?
1,balance 是允许被多次修改的,所以,另一个线程执行了 balance=balance-amount 是逻辑上正确的;
2,lock 是防止脏读,也就是你需要修改的 balance 的值,并不是你上次读取到的 balance 的值。
看这段代码:
lock(this) 所有的调用线程都会阻塞在这里,只有一个线程会被允许进入下面的代码;
if(balance >= amount)
balance = balance - amount;
// 因为前面加了 lock ,所以可以确保判断语句读取到的 balance 的值和修改语句读取到的 balance 的值是一样的,那么这就确保了在共享变量 balance 上的修改操作是原子性的,不会发生数据不一致性。
当前线程执行完后就退出了,那么在 lock(this)上等待的其它线程会有一个被允许进入此段代码,这就是你的疑惑点,但是这是正确的,因为不论从逻辑上还是业务规则上,balance 都是允许被多次修改的,我们这里放置 lock,是为了避免要修改的值并不是我们先前读取到的值的问题。
我指的是前面 if (balance < 0)这个判断,lock(this) 所有的调用线程都会阻塞在这里,只有一个线程会被允许进入下面的代码;那么当进入的线程改变了balance的值使得它小于0了,所以是不是lock应该放在if (balance < 0)之前? 谢谢
@While蹒跚学步...: 交易判断的依据是 balance >= amount。if(balance < 0) 是永远都不应该发生的情况,所以原文有句注释 “ file://如果balance小于0则抛出异常 throw new Exception("Negative Balance"); ”。
@Launcher: 明白了,非常感谢