有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpringMVC单线程安全?

我有一个单例Springbean(默认范围)。因此,一个实例将被多个线程使用。然而,我对线程安全有点困惑,显然所有Springbean都是线程安全的,如果它们是无状态的,但是我的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和use wait/notify等

非常感谢


共 (4) 个答案

  1. # 1 楼答案

    如果在初始化后在上下文中将类标记为singleton,那么类将不会是线程安全的 带有“new”的字段是手动的,这会在创建bean时发生,并且在内存中会有一个实例,比如singleton,因此,线程共享CustomGxSessionIdCacheImpl、PcrfRecord等实例

    如果可以让这些实例在spring上下文的控制下运行,比如:

    <bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype">
    

    并在PcrfSimulator中自动连接它们,如:

    @Autowired
    private final CustomGxSessionIdCacheImpl gxSessionIdCache
    

    之后,只要代码访问gxSessionIdCache,spring就会分别为每个访问和每个线程创建一个新实例。Singleton中的任何其他方法都必须用synchronized标记,因为这些方法对多线程访问是开放的。春季单身人士是普通单身人士

    我认为,如果你根本没有状态,那么一切都是线程安全的,这是错误的。如果你认为是低级的,那么这些方法也有状态,即局部变量,如果多个线程访问这些状态,你也会头疼

  2. # 2 楼答案

    正如已经确定的那样,您的类不是线程安全的。Prototype scope是一种方法,但是如果Prototype scope bean被自动连接到singleton bean中,这仍然意味着只创建了Prototype bean的一个实例,实际上也使其成为singleton

    同步是另一种方式,但这只适用于实例变量意味着在线程之间共享的情况。然而,如果意图是实例变量对于每个线程都应该是唯一的,那么您应该查看^{}

  3. # 3 楼答案

    Spring本身确保在bean被实例化、注入等之后正确地发布它们。这意味着任何引用了你的单例bean的线程至少会看到它在Spring上下文创建结束时的状态

    如果状态是不变的,你就没有什么可做的

    但是,如果单例的状态是可变的,则必须正确地同步对该可变状态的访问

  4. # 4 楼答案

    volatile没有帮助。它只会确保值真正更新

    易变手段(http://www.javamex.com/tutorials/synchronization_volatile.shtml):

    • The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory";
    • Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.

    只有当控制流在对共享变量的第一次写入和最后一次读取之间从未退出(外部)同步块,并且所有共享变量仅在使用相同锁对象的同步块内访问时,使方法同步才有帮助

    因此,一般的解决方案是防止在这种情况下共享变量。使类不可变的一个简单方法是使用局部变量和方法参数,而不是共享实例变量


    你写道:“如果SpringBean是无状态的,那么它们是线程安全的,但我的bean不是无状态的。”——好的,这个主题在上面的段落中讨论过

    但从代码中可以看出,这不是问题所在final标记的变量,因此它们是不可变的。如果该对象的字段以相同的方式运行(未更新或有足够的保护以防止并发修改问题),则没有可变的共享变量。有时这被称为“有效无状态”。这意味着这些值不会改变。所以这对并发性没有问题(因为并发性问题是关于改变值的)

    最后:如果字段(PcrfRecord…),您可以在不同的线程中使用示例中的有效无状态类,而无需同步块他们实际上是无国籍的。(如果字段PcrfRecord…不是无状态的,那么类PcrfSimulator就不能被称为有效无状态的)——但这与Spring无关,它是纯Java

    顺便说一句:如果你的变量是final,你不需要让它们volantile