使用lock确保线程安全

当多个线程同时访问共享区时,就会产生线程安全问题。
例如:

using System;
using System.Threading;

class Account
{
int balance;

Random r = new Random();

public Account(int initial)
{
balance = initial;
}

int Withdraw(int amount)
{

if (balance < 0)
{
throw new Exception("Negative Balance");
}

// Comment out the next line to see the effect of leaving out
// the lock keyword:

if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0;
}

}

public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}

class Test
{
public static void Main()
{
Thread[] threads = new Thread[10]; //10个线程访问共享区
Account acc = new Account (1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}

程序改为,即可:
using System;
using System.Threading;

class Account
{
int balance;

Random r = new Random();

public Account(int initial)
{
balance = initial;
}

int Withdraw(int amount)
{

// This condition will never be true unless the lock statement
// is commented out:
if (balance < 0)
{
throw new Exception("Negative Balance");
}

// Comment out the next line to see the effect of leaving out
// the lock keyword:
lock (this)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
}

public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}

class Test
{
public static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account (1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}

这个就像版本控制中的原理。lock也可以解决singleton中的多线程不安全问题。

这里给出一个懒人模式的singleton的线程安全代码:

public sealed class SingletonTest

{
private SingletonTest()
{
//TODO:一些初始化
}
//m_instance申明为volatile则,当变量申明完成后才能访问。
private static volatile SingletonTest m_instance = null;

private static Object sync = new Object();
public static SingletonTest createInstance()
{
if(m_instance == null)
{
lock(sync)
{
m_instance = new SingletonTest();
}
}
return m_instance;
}
}

Published At
Categories with Web编程
Tagged with
comments powered by Disqus