从抽象 class 使线程安全 class
Making a thread safe class from an abstract class
一个设计问题。我知道这个方法是线程安全的,但是从设计的角度,有没有更好的方法呢?
我有一个抽象class(不是线程安全的):
public abstract class Class1
{
protected someobject myobject;
public Class1()
{
myobject = new someoject();
}
public virtual void proc1()
{
// do something with my object
}
public virtual void proc2()
{
// do something with my object
}
public virtual void proc3()
{
// do something with my object
}
}
现在我想从这个 class 创建一个需要线程安全的后代,所以我这样做:
public class Class2: Class1
{
private static readonly object obj = new object();
public override void proc1()
{
lock(obj)
{
base.proc1();
}
}
public override void proc2()
{
lock(obj)
{
base.proc2();
}
}
public override void proc3()
{
lock(obj)
{
base.proc3();
}
}
}
我可以使基本线程安全,但我有一些其他 class 继承自相同的基本并且不需要线程安全,所以我不想强制线程安全。这样的设计有什么问题吗?如果基地有很多 public 成员,那就有点乏味了....
很难推断出您的代码的潜在用途,但从一般考虑的角度来看,我会强调以下问题:
- 责任。我正在查看
Class2
代码,发现与基本 class 相比,除了基本 class 方法的竞争条件保护外,它没有做任何额外的事情。通常我们倾向于对特定的状态强加线程安全,以保证并发访问条件下的状态一致性。但是在这种情况下,Class2
根本不知道它保护的行为是否会导致竞争条件。如果 Class1
以不再需要线程安全的方式修改怎么办 - 我们将在 Class2
class 中拥有冗余锁(或者将删除它们与 Class1
).如果 Class1
使用其他方法扩展,或者更糟糕的是有人决定通过另一个锁对象向 Class1
添加额外的线程安全性(在最坏的情况下我们可能会出现死锁)。因此,每次我们在 Class1
中进行此类更改时,我们还必须检查 Class2
代码以确保没有任何问题,换句话说,我们在这些 class 之间紧密耦合只是因为Class2
有不该有的责任。
- LSP。当我们谈论 classes 的层次结构时,我们通常会记住,无论使用何种类型的层次结构,层次结构合同的使用要求都不应该不同。在层次结构中线程安全和非线程安全 classes 对该层次结构的使用施加了额外的限制。特别是消费者应该知道它在什么情况下处理什么类型的实例,这可能排除了可以使用符合 LSP 的层次结构的场景数量。例如,消费者将无法使用集合
Class1
在一般场景中,除非它明确知道场景是线程安全的。
一般建议:
- 我会尽量避免在子 classes 中引入一种行为,这可能取决于可以使用子 classes 的上下文。我会尝试使整个层次结构保持一致:层次结构中的所有 classes 都是线程安全的,或者它们都不是。
- 如果层次结构中的一些 classes 需要线程安全,而另一些则不需要,这可能表明层次结构契约的内聚性低。我会尝试将基础 class 和子 class 分解成更小的部分,这可能意味着多个合同和可能的层次结构。
- 如果基础 class 或其他 classes 保持可能在不同并发上下文中使用的状态,并且从线程安全的角度来看仍然很难实现同质层次结构,我' d 考虑将同步逻辑移到层次结构中的 classes 之外,并将此责任留给消费者。
如果您想以线程安全的方式使用 Class1
(或后代 class),您应该使用封装而不是像 Kevin Gosse 所说的继承。不应该以这种方式使用继承,因为如果 Class1
有更多非虚拟的方法(甚至可能 public)会改变对象的内部状态,您将无法控制它们。您应该采用并封装一个继承 Class1
的 class,然后公开将作为线程安全方法调用的方法。
即使你做controlClass1
设计,每次添加或更改Class1
时都想到Thread安全继承者(Class2
)也是一个糟糕的设计'方法
一个设计问题。我知道这个方法是线程安全的,但是从设计的角度,有没有更好的方法呢?
我有一个抽象class(不是线程安全的):
public abstract class Class1
{
protected someobject myobject;
public Class1()
{
myobject = new someoject();
}
public virtual void proc1()
{
// do something with my object
}
public virtual void proc2()
{
// do something with my object
}
public virtual void proc3()
{
// do something with my object
}
}
现在我想从这个 class 创建一个需要线程安全的后代,所以我这样做:
public class Class2: Class1
{
private static readonly object obj = new object();
public override void proc1()
{
lock(obj)
{
base.proc1();
}
}
public override void proc2()
{
lock(obj)
{
base.proc2();
}
}
public override void proc3()
{
lock(obj)
{
base.proc3();
}
}
}
我可以使基本线程安全,但我有一些其他 class 继承自相同的基本并且不需要线程安全,所以我不想强制线程安全。这样的设计有什么问题吗?如果基地有很多 public 成员,那就有点乏味了....
很难推断出您的代码的潜在用途,但从一般考虑的角度来看,我会强调以下问题:
- 责任。我正在查看
Class2
代码,发现与基本 class 相比,除了基本 class 方法的竞争条件保护外,它没有做任何额外的事情。通常我们倾向于对特定的状态强加线程安全,以保证并发访问条件下的状态一致性。但是在这种情况下,Class2
根本不知道它保护的行为是否会导致竞争条件。如果Class1
以不再需要线程安全的方式修改怎么办 - 我们将在Class2
class 中拥有冗余锁(或者将删除它们与Class1
).如果Class1
使用其他方法扩展,或者更糟糕的是有人决定通过另一个锁对象向Class1
添加额外的线程安全性(在最坏的情况下我们可能会出现死锁)。因此,每次我们在Class1
中进行此类更改时,我们还必须检查Class2
代码以确保没有任何问题,换句话说,我们在这些 class 之间紧密耦合只是因为Class2
有不该有的责任。 - LSP。当我们谈论 classes 的层次结构时,我们通常会记住,无论使用何种类型的层次结构,层次结构合同的使用要求都不应该不同。在层次结构中线程安全和非线程安全 classes 对该层次结构的使用施加了额外的限制。特别是消费者应该知道它在什么情况下处理什么类型的实例,这可能排除了可以使用符合 LSP 的层次结构的场景数量。例如,消费者将无法使用集合
Class1
在一般场景中,除非它明确知道场景是线程安全的。
一般建议:
- 我会尽量避免在子 classes 中引入一种行为,这可能取决于可以使用子 classes 的上下文。我会尝试使整个层次结构保持一致:层次结构中的所有 classes 都是线程安全的,或者它们都不是。
- 如果层次结构中的一些 classes 需要线程安全,而另一些则不需要,这可能表明层次结构契约的内聚性低。我会尝试将基础 class 和子 class 分解成更小的部分,这可能意味着多个合同和可能的层次结构。
- 如果基础 class 或其他 classes 保持可能在不同并发上下文中使用的状态,并且从线程安全的角度来看仍然很难实现同质层次结构,我' d 考虑将同步逻辑移到层次结构中的 classes 之外,并将此责任留给消费者。
如果您想以线程安全的方式使用 Class1
(或后代 class),您应该使用封装而不是像 Kevin Gosse 所说的继承。不应该以这种方式使用继承,因为如果 Class1
有更多非虚拟的方法(甚至可能 public)会改变对象的内部状态,您将无法控制它们。您应该采用并封装一个继承 Class1
的 class,然后公开将作为线程安全方法调用的方法。
即使你做controlClass1
设计,每次添加或更改Class1
时都想到Thread安全继承者(Class2
)也是一个糟糕的设计'方法