Java SpringMVC单线程安全?
我有一个单例Springbean(默认范围)。因此,一个实例将被多个线程使用。然而,关于线程安全,我有点困惑,显然所有Springbean都是线程安全的,如果它们是无状态的,但是我的bean不是无状态的,它有各种实例变量,每个请求/其他控制器/类都使用这些变量 以下是我的单例bean的开始:Java SpringMVC单线程安全?,java,spring,spring-mvc,thread-safety,singleton,Java,Spring,Spring Mvc,Thread Safety,Singleton,我有一个单例Springbean(默认范围)。因此,一个实例将被多个线程使用。然而,关于线程安全,我有点困惑,显然所有Springbean都是线程安全的,如果它们是无状态的,但是我的bean不是无状态的,它有各种实例变量,每个请求/其他控制器/类都使用这些变量 以下是我的单例bean的开始: public class PcrfSimulator { private final CustomGxSessionIdCacheImpl gxSessionIdCache = new CustomGxS
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();
}
公共类PcrfSimulator{
私有最终CustomGxSessionIdCacheImpl gxSessionIdCache=new CustomGxSessionIdCacheImpl();
私有最终PcrfRecord pcrfRec=新PcrfRecord();
私有最终ResponseConditions ResponseConditions=新ResponseConditions();
public CustomGxSessionIdCacheImpl getGxSessionIdCache(){
返回gxSessionIdCache;
}
公共ArrayList getRules(){
返回pcrfRec.getRules();
}
因此,上面的字段将由多个线程访问-将这些字段标记为volatile就足够了,还是我必须将访问这些字段的方法(不仅在这个类中有很多,而且在其他控制器/类中也有很多)标记为synchronized和use wait/notify等
非常感谢!
volatile
没有帮助。它只会确保值真正更新
易变手段(http://www.javamex.com/tutorials/synchronization_volatile.shtml):
- 这个变量的值永远不会被本地线程缓存:所有读写操作都将直接进入“主内存”
- 对变量的访问就像它被封装在一个同步块中一样,在其自身上是同步的
您写道“如果SpringBean是无状态的,那么它们是线程安全的,但是我的bean不是无状态的。”——好的,这一主题在上面的段落中讨论过 但是从您的代码中可以看出这不是问题所在!标有
final
的变量是不可变的。如果该对象的字段以相同的方式运行(未更新或有足够的保护以防止并发修改问题)您没有可变的共享变量。有时这被称为“有效无状态”。这意味着值不会更改。因此,并发性没有问题(因为并发性问题与更改值有关)
最后:如果字段(PcrfRecord
..)是有效无状态的,则可以在不同线程中使用示例中的有效无状态类,而不使用同步块。(如果字段PcrfRecord
..不是无状态的,则类PcrfSimulator
不能称为有效无状态)--但这与Spring无关,它是纯Java
顺便说一句:如果你的变量是
final
,你不需要让它们volantileSpring本身确保在bean被实例化、注入等之后正确地发布它们。这意味着任何引用你的单例bean的线程都至少会看到它在Spring上下文结束时的状态t创造
如果状态是不可变的,则无需执行任何操作
如果单例的状态是可变的,那么您必须正确地同步对此可变状态的访问。如果您在初始化后在上下文中将其标记为单例,则您的类将不会是线程安全的
带有“new
”的字段是手动的,这在创建bean时会发生一次,您的内存中会有一个实例,比如singleton,因此,您的线程共享CustomGxSessionIdCacheImpl、PcrfRecord等实例
如果可以使这些实例在spring上下文的控制下运行,例如:
<bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype">
之后,只要您在gxSessionIdCache上进行代码访问,spring就会为每个访问和每个线程分别创建一个新实例。Singleton中的任何其他方法都必须标记为synchronized
,因为这些方法是为多线程访问打开的。spring Singleton是常规的Singleton
我认为,说如果你根本没有状态,那么一切都是线程安全的是错误的。如果你认为低级别,方法也有状态,即局部变量,如果多个线程访问这些,你也会感到头疼。正如已经建立的那样,你的类不是线程安全的。原型范围是一种方法,但如果原型范围的bean被自动连接到一个单例bean中,这仍然意味着只创建了原型bean的一个实例,有效地使其成为单例bean
同步是另一种方式,但这只适用于实例变量要在线程之间共享的情况。但是,如果目的是实例变量对每个线程都是唯一的,那么您应该改为查看。谢谢,但这不意味着我将有多个缓存实例吗?我只需要一个cache,由所有线程访问和更新。您还必须将缓存的方法标记为已同步。这很清楚。我不明白为什么在上面的示例中范围是原型,为什么不将其保留为单实例?谢谢Ralph,但final不只是意味着它们只能实例化一次吗?我这么说是因为在代码中,最终的变量是e的更新方式如下:gxSessionIdCache.addIpAddress(gxSessionId,ipAddress)-实际上,当它们作为参数传递给不使用最终字段的方法时,它们会被更新-例如doStuff(gxSessionIdCache gxSessionIdCache){…}我假设
@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache