我有一个单例Spring bean (默认作用域)。因此,一个实例将被多个线程使用。然而,我对线程安全有点困惑,显然,如果所有Spring bean都是无状态的,那么它们都是线程安全的,但我的bean不是无状态的,它有各种实例变量,供每个请求/其他控制器/类使用。
下面是我的单例bean的开始:
public class PcrfSimulator {
private final CustomGxSessionIdCacheImpl gxSessionIdCache = new CustomGxSessionIdCacheImpl();
private final PcrfRecord pcrfRec = new PcrfRecord();
private final ResponseConditions responseConditions = new ResponseConditions();
public CustomGxSessionIdCacheImpl getGxSessionIdCache() {
return gxSessionIdCache;
}
public ArrayList<Rule> getRules() {
return pcrfRec.getRules();
}因此,上面的字段将被多个线程访问--将这些字段标记为volatile是否足够,或者我是否必须将访问它们的方法(不仅是这个类,还有其他控制器/类)标记为synchronized并使用wait/notify等?
非常感谢!
发布于 2012-02-21 19:04:14
volatile帮不上忙。它只会确保值真正更新。
易失性均值(http://www.javamex.com/tutorials/synchronization_volatile.shtml):
此变量的值永远不会以线程方式缓存到本地:所有读取和写入操作都将直接转到"main memory";
只有当您的控制流在第一次写入和最后一次读取共享变量之间从不退出(外部) synchronized块,并且所有共享变量仅在使用相同锁对象的同步块中访问时,使方法同步才有帮助。
因此,一般的解决方案是在这种情况下防止共享变量。使类不可变的一种简单方法是使用局部变量和方法参数,而不是共享实例变量。
你写道:“如果Spring bean是无状态的,那么它们是线程安全的,但我的bean不是无状态的。”--好的,这个主题将在上面的段落中讨论。
,但是从你的代码中可以看出这不是问题所在!标记为final的变量,这样它们就是不可变的。如果该对象的字段行为相同(没有更新或针对并发修改问题提供了足够的保护),那么就没有可变的共享变量。有时这被称为“有效的无状态”。这意味着这些值不会改变。所以这对于并发性来说是没有问题的(因为并发性问题是关于变更值的)。
最后:您可以在不同的线程中使用这个来自示例的有效的无状态类,而无需使用synchronized块,如果字段(PcrfRecord...)是有效的无状态。(如果字段为PcrfRecord...不是无状态的,那么类PcrfSimulator就不能被称为有效的无状态) --但这与Spring无关,它是纯Java。
顺便说一句:如果你的变量是final,你不需要让它们变成volantile。
发布于 2012-02-21 19:10:58
Spring本身确保在bean被实例化、注入等之后正确地发布它们。这意味着任何引用了单例bean的线程至少会看到它在Spring上下文创建结束时的状态。
如果状态是不可变的,你就什么也不用做了。
但是,如果单例的状态是可变的,则必须正确同步对此可变状态的访问。
发布于 2012-02-21 19:16:07
如果您在上下文中将其标记为单例,那么您的类将不是线程安全的,因为您使用"new“手动初始化字段,这在创建bean时发生一次,并且在内存中将有一个实例,就像您的单例一样,因此,您的线程共享CustomGxSessionIdCacheImpl、PcrfRecord等的实例。
如果您可以使这些实例处于spring上下文的控制之下,例如:
<bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype">并在PcrfSimulator中自动生成它们,如下所示:
@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache在此之后,只要您的代码访问gxSessionIdCache,spring就会分别为每个访问和每个线程创建一个新实例。单例中的任何其他方法都必须标记为synchronized,因为这些方法对于多线程访问是开放的。Spring单例是常规的单例。
我认为,如果你根本没有状态,那么一切都是线程安全的,这是错误的。如果你认为低级,方法也有状态,即局部变量,如果多线程访问这些变量,你也会感到头疼。
https://stackoverflow.com/questions/9376291
复制相似问题