我最近在一个类似于下面的测试中遇到了一个面试问题,我没有很多使用线程开发的经验,有人可以帮助建议我如何处理这个问题吗?:
public class StringQueue
{
private object _lockObject = new object();
private List<string> _items = new List<string>();
public bool IsEmpty()
{
lock (_lockObject)
return _items.Count == 0;
}
public void Enqueue(string item)
{
lock (_lockObject)
_items.Add(item);
}
public string Dequeue()
{
lock (_lockObject)
{
string result = _items[0];
_items.RemoveAt(0);
return result;
}
}
}
Run Code Online (Sandbox Code Playgroud)
以上方法的线程是否安全?为什么?
public string DequeueOrNull()
{
if (IsEmpty())
return null;
return Dequeue();
}
Run Code Online (Sandbox Code Playgroud)
在我看来答案是否定的.
当isEmpty()过程锁定对象时,它会在返回调用后立即释放 - 另一个线程可能在调用IsEmpty()和Dequeue()之间调用DequeueOrNull()(此时对象被解锁),因此删除了唯一存在的项目,使Dequeue()在那时无效.
一个合理的解决方法是将锁定放在DequeueOrNull()中的两个语句上,因此在检查之后但在DeQueue()之前没有其他线程可以调用DeQueue().