Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SpringMVC单线程安全?_Java_Spring_Spring Mvc_Thread Safety_Singleton - Fatal编程技术网

Java SpringMVC单线程安全?

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

我有一个单例Springbean(默认范围)。因此,一个实例将被多个线程使用。然而,关于线程安全,我有点困惑,显然所有Springbean都是线程安全的,如果它们是无状态的,但是我的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();
}
公共类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
,你不需要让它们
volantile

Spring本身确保在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