56

Spring对象线程安全吗?如果没有,如何使它们线程安全?

4

2 回答 2

131

这是两个不相关的问题:

Spring Beans 线程安全吗?

不。

Spring 有不同的 bean作用域(例如 Prototype、Singleton 等),但所有这些作用域都是在创建 bean时强制执行的。例如,每次“注入”该 bean 时都会创建一个“原型”作用域 bean,而“单例”作用域 bean 将被创建一次并在应用程序上下文中共享。还有其他范围,但它们只是定义了何时创建新实例的时间跨度(例如“范围”)。

以上与线程安全几乎没有关系,因为如果多个线程可以访问一个bean(无论范围如何),它只取决于该bean的设计是否是“线程安全的” .

我说“很少,如果有的话”的原因是因为它可能取决于您要解决的问题。例如,如果您担心 2 个或更多 HTTP 请求是否可能对同一个 bean 产生问题,则有一个“请求”范围将为每个 HTTP 请求创建一个新的 bean 实例,因此您可以“考虑”一个在多个 HTTP 请求的上下文中,特定的 bean 是“安全的”。但是Spring仍然不是真正的线程安全,因为如果多个线程在同一个HTTP 请求中使用这个 bean,它会回到 bean 设计(的 bean 支持类的设计)。

如何制作/设计线程安全的“对象”?

有几种方法,可能太长,无法在此处列出,但这里有一些示例:

  • 将您的 bean 设计为不可变的:例如,没有设置器,仅使用构造函数参数来创建 bean。还有其他方式,比如Builder pattern等。

  • 设计你的 bean无状态:例如,做某事的 bean可以只是一个函数(或多个)。在大多数情况下,这个 bean 可以并且应该是无状态的,这意味着它没有任何状态,它只使用您每次提供的函数参数(在每次调用时)

  • 设计你的 bean持久化:这是“不可变”的一个特例,但有一些非常好的属性。通常用于函数式编程,其中 Spring(至少目前)不如在命令式世界中有用,但我已将它们与 Scala/Spring 项目一起使用。

  • 用锁设计你的 bean [最后的手段]:除非你正在使用较低级别的库,否则我建议不要这样做。原因是我们(人类)在锁方面的想法不好。就像我们被抚养和培养的方式一样。一切都是并行发生的,我们不需要“暂停下雨,让我拿把伞”。然而,当你在谈论“同时做多件事”时,计算机都是关于锁的,因此我们中的一些人(特殊的人)正在做他们的公平份额并基于这些锁实现库。大多数其他人可以只使用这些库而不必担心并发性。

于 2013-04-01T16:33:39.630 回答
12

Spring 不保证线程安全。但它提供了有关此事的指导方针。如果您的 bean 有状态,请不要使用单例 bean 范围。

我创建了一个演示来展示带有 Singleton 和 Prototype 范围的 spring bean 的可变性

我专注于有状态的 bean,然后使用 Singleton 和 Prototype 范围来展示 bean 如何改变它们的状态。

Job 类由 JobPrototype 和 JobSingleton bean 扩展,它们基于活动的配置文件集加载。Tp 设置配置文件,将属性 spring.profiles.active 设置为 proto(对于原型范围)或单例(对于单例范围)

活动作业 beanAutowired位于 Runner 和 Runner1 bean 中,它们具有定期改变Autowiredbean状态的调度方法

public class Job {

    protected int count = 0;

    void counter() {
        this.count++;
    }

    public int getCount() {
        return count;
    }
}



@Component
@Profile("proto")
@Scope("prototype")
public class JobPrototype extends Job {
}

@Component
@Profile("singleton")
public class JobSingleton extends Job {

}

@Component
public class Runner {

    private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private Job job;

    @Scheduled(fixedDelay = 1500)
    void count() {
        this.job.counter();
        Log.info("### Runner: count: " + this.job.getCount());
    }
}

@Component
public class Runner1 {

    private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private Job job;

    @Scheduled(fixedDelay = 1000)
    void count() {
        this.job.counter();
        Log.info("### RunnerOne: count: " + this.job.getCount());
    }

}

结果是

  1. 单 例单例范围

  2. 原型 原型范围

此演示的完整代码beans_mutability

于 2018-11-27T10:19:42.880 回答