猿问

实例化新实例是否使所有代码线程安全?

编辑代码以使其成为线程安全的帖子评论


请参阅最后更新的问题。


你能帮我理解这段代码是线程安全的还是如何使它成为线程安全的?


设置


我的系统有一个非常简单的类,称为 WorkItem。


public class WorkItem

{

    public int Id {get;set;}

    public string Name {get;set;}

    public DateTime DateCreated {get;set;}

    public IList<object> CalculatedValues {get;set;}    

}

有一个接口 ICalculator,它有一个方法,它接受一个工作项,执行计算并返回 true。


public interface ICalculator

{

    bool Calculate(WorkItem WorkItem);

}

假设我们有两个 ICalculator 的实现。


public class BasicCalculator: ICalculator

{

    public bool Calculate(WorkItem WorkItem)

    {

        //calculate some value on the WorkItem and populate CalculatedValues property 

        return true;

    }

}

另一个计算器:


public class AnotherCalculator: ICalculator

{

    public bool Calculate(WorkItem WorkItem)

    {

        //calculate some value on the WorkItem and populate CalculatedValues property

        //some complex calculation on work item

        if (somevalue==0) return false;

        return true;

    }


最后,在我的客户端类中,我注入了与运行相关的 ICalculators[]。然后我实例化 ExecuteCalculators() 方法。


现在我有大量的工作项,我想对它们执行计算,所以我创建了一个任务列表,其中每个任务负责实例化 CalculatorHandler 实例,然后获取一个工作项并通过执行 WaitAll() 来执行计算所有的任务


这是系统的简化版本。实际系统有一系列计算器,Calculators 和 CalculatorHandler 是通过 IoC 等注入的。


我的问题是 - 帮助我理解以下几点:

  1. 每个任务都会创建一个 CalculatorHandler 的新实例。这是否意味着 CalculatorHandler 中发生的任何事情都是线程安全的,因为它没有任何公共属性并且只是在计算器上循环?

  2. 计算器在所有任务之间共享,因为它们是 Client 类的成员变量,但它们被传递到为每个任务实例化的 CalculatorHandler。这是否意味着当所有任务运行时,由于创建了 CalculatorHandler 的新实例,因此 Calculators 是自动线程安全的,我们不会遇到任何线程问题,例如死锁等?

  3. 你能建议我如何使代码线程安全吗?是否最好将Func<'ICalculators>'[]传递给 Client 类,然后在每个任务中,我们可以执行 Func<'ICalculator'>() 然后将这些实例传递给 ICalculator 那里?Func<'ICalculator'> 将返回 ICalculator 的实例。

  4. 计算器是作为私有方法变量传入的,因此 CalulatorHandler 的其他实例不能运行相同的计算器实例,这是真的吗?还是因为计算器是引用类型,我们必然会遇到多线程问题?



小唯快跑啊
浏览 158回答 2
2回答

尚方宝剑之说

不,它不是线程安全的。如果在任何计算中存在任何共享状态,则可能存在线程问题。避免线程问题的唯一方法是确保您没有更新任何共享状态。这意味着只读对象和/或使用“纯”函数。您已经使用了“共享”这个词——这意味着由于共享状态而不是线程安全的。除非你的意思是“分布式”而不是“共享”。独占使用只读对象。它们是引用类型,因此它们可以在不同的线程之间共享——因此不是线程安全的——除非它们是只读的。下面是一个只读对象的例子:public sealed class WorkItem : IEquatable<WorkItem>{&nbsp; &nbsp; private readonly int _id;&nbsp; &nbsp; private readonly string _name;&nbsp; &nbsp; private readonly DateTime _dateCreated;&nbsp; &nbsp; public int Id { get { return _id; } }&nbsp; &nbsp; public string Name { get { return _name; } }&nbsp; &nbsp; public DateTime DateCreated { get { return _dateCreated; } }&nbsp; &nbsp; public WorkItem(int id, string name, DateTime dateCreated)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _id = id;&nbsp; &nbsp; &nbsp; &nbsp; _name = name;&nbsp; &nbsp; &nbsp; &nbsp; _dateCreated = dateCreated;&nbsp; &nbsp; }&nbsp; &nbsp; public override bool Equals(object obj)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (obj is WorkItem)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Equals((WorkItem)obj);&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; }&nbsp; &nbsp; public bool Equals(WorkItem obj)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (obj == null) return false;&nbsp; &nbsp; &nbsp; &nbsp; if (!EqualityComparer<int>.Default.Equals(_id, obj._id)) return false;&nbsp; &nbsp; &nbsp; &nbsp; if (!EqualityComparer<string>.Default.Equals(_name, obj._name)) return false;&nbsp; &nbsp; &nbsp; &nbsp; if (!EqualityComparer<DateTime>.Default.Equals(_dateCreated, obj._dateCreated)) return false;&nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; }&nbsp; &nbsp; public override int GetHashCode()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; int hash = 0;&nbsp; &nbsp; &nbsp; &nbsp; hash ^= EqualityComparer<int>.Default.GetHashCode(_id);&nbsp; &nbsp; &nbsp; &nbsp; hash ^= EqualityComparer<string>.Default.GetHashCode(_name);&nbsp; &nbsp; &nbsp; &nbsp; hash ^= EqualityComparer<DateTime>.Default.GetHashCode(_dateCreated);&nbsp; &nbsp; &nbsp; &nbsp; return hash;&nbsp; &nbsp; }&nbsp; &nbsp; public override string ToString()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return String.Format("{{ Id = {0}, Name = {1}, DateCreated = {2} }}", _id, _name, _dateCreated);&nbsp; &nbsp; }&nbsp; &nbsp; public static bool operator ==(WorkItem left, WorkItem right)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (object.ReferenceEquals(left, null))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return object.ReferenceEquals(right, null);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return left.Equals(right);&nbsp; &nbsp; }&nbsp; &nbsp; public static bool operator !=(WorkItem left, WorkItem right)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return !(left == right);&nbsp; &nbsp; }}一旦创建就无法修改,因此线程安全不再是问题。现在,如果我可以假设每一个ICalculator都是在没有状态的情况下实现的,因此是一个纯函数,那么计算就是线程安全的。但是,您的问题中没有任何内容让我知道我可以做出这个假设。因此,任何人都无法告诉您您的代码是线程安全的。因此,考虑到只读WorkItem和纯ICalculator函数,您的其余代码看起来会非常好。
随时随地看视频慕课网APP
我要回答