单例 Bean 如何服务于并发请求?

我有一个关于单例 bean 如何服务并发请求的详细问题。

关于这个问题,我已经在 StackOverflow 上搜索过了。这是一个样本 来自堆栈溢出的链路,但我发现只有高层次的细节。我需要关于单一 bean 如何服务并发请求以及系统处理器如何查看这些请求的详细信息。

对系统处理器中的并发请求处理进行了在线研究。他们说处理器本身有一个调度程序,调度程序将决定处理哪个请求。

好的,假设我有多个核心处理器,那么调度程序如何处理并发请求?

有人能给我解释一下单例 bean 如何在 JVM 和系统中服务并发请求的逐步过程吗?

让我用一个具体的例子来解释,我有一个类似 Sports的类:

class Sports {
public void playFootball() {
}


public void playVolleyBall() {
}
}

有两个请求。第一个请求是在类 Sports的创建的单例实例上执行 playFootball方法。同时,另一个请求是在类 Sports的同一个创建的单例实例上执行 playVolleyBall方法。

单例实例是如何实现的?

45133 次浏览

Singleton 是一个 bean 范围。您必须处理如何为多线程访问服务的问题。可以使用同步或并发包。档号: Spring 单例 bean 线程安全吗?

对于并发请求,单个 bean 将逐个服务于多个请求。

要详细了解单例 Bean 如何服务于并发请求? 你必须知道以下关于春豆的事情

  • 望远镜

    Spring 有不同的 bean 作用域(例如 Prototype、 Singleton 等) ,但所有这些作用域都是在创建 bean 时实施的。 例如,每次“注入”这个 bean 时,都会创建一个“原型”范围内的 bean。 而“ singleton”范围内的 bean 将创建一次并在应用程序上下文中共享。
    “ singleton”作用域是 Spring Bean 的默认作用域

  • 豆子的创造

    Spring Bean 的整个生命周期由 Spring 容器(即 ApplicationContext/BeanFacotry)管理 Spring Container 在内部引用 bean 定义(即基于 XML 的注释)来创建实际的实例 该 bean 定义定义的类的。 现在,当 Spring Container 启动时,它将引用 bean 定义并实例化所有已定义的 bean

  • 请求魔豆。

    现在,当对象向 bean 发出请求时,Spring Container 将切换已经初始化的 bean。

  • 弹簧豆范围

  • Spring 对象线程安全吗?

  • Spring 教程11-了解 Bean 作用域

希望这个能帮到你。

理想的单例 bean 不应该保持任何状态。这意味着它不会有任何变量来存储特定于它所服务的请求的任何内容。

因此,一个单例 bean 将只有无状态的代码(例如控制器方法) ,可以对多个请求并发执行,而不存在任何并发问题。

例如,如果下面是您的单例 bean:

@Service
public class Calculator {


public int sum(int a, int b) {
return a + b;
}


}

简单地说,当两个“请求”同时调用 bean 的 sum方法时,这意味着 sum方法将在两个不同的线程中并发执行。因此,它们将有自己的执行上下文,这些上下文不会彼此重叠。这将使它们能够安全地并发运行。

如果同一个 bean 具有如下状态:

@Service
public class Calculator {


int incrementalMultiplier = 0;


public int mulitply(int a, int b) {
incrementalMultiplier++;
return a * b * incrementalMultiplier;
}


}

这可能会在同时服务两个请求时引起问题,因为 incrementalMultiplier是两个请求(线程)共享的对象级状态,因此可能会产生意外的结果。

简而言之,由于 他们会处于不同的境地。,无状态单例模式将能够同时处理两个请求

萨拉万 · 库马尔,

我明白你问这个问题的动机。在我开始编译器工作之前,我也有一个非常相似的想法,那就是了解 Java 虚拟机的内部结构。

首先,你的问题让我印象深刻。为了解决你的问题,需要有几点区别和理解。首先: 一个单例模式,有时甚至称为反模式,确保这个类只有一个实例可用于 JVM (Java 虚拟机)。这意味着我们实际上是在应用程序中引入了一个全局状态。我知道你明白这一点,但这只是一个澄清点。

现在是内部结构。

当我们创建一个类的实例时,我们正在创建一个驻留在 JVM 的共享内存中的对象。现在,这些线程正在独立执行对这些实例进行操作的代码。每个线程都有一个工作内存,用于保存所有线程共享的主内存中的数据。这是对已创建的 Singleton 对象的引用所在的位置。实际上,生成的字节码代表了您创建的单例对象,这些字节码正在这些线程中的每一个线程上执行。

现在这种情况发生的内部原因如下:

每个 JVM 线程都有一个私有的 JVM 堆栈,与线程同时创建。现在,JVM 有一个在所有 JVM 线程之间共享的堆。堆是分配所有类实例和数组的内存的运行时数据区域。堆是在 VM 启动时创建的。当线程请求单例实例时,它将指向堆中的一个引用,这个单例实例的字节码就驻留在这个堆中。它将执行适当的代码。在您的示例中,它将为第一个请求执行第一个方法,为第二个请求执行第二个方法。之所以能够这样做,是因为没有任何锁或限制阻止编译器将程序计数器指向分配此实例的堆中的区域。Singleton 类对 Java 虚拟机的唯一限制是它在这个类的堆中只能有一个实例。就这么简单。除此之外,您可以从您的方法中引用它100次,编译器将指向相同的字节码并简单地执行它。这就是为什么我们通常希望 Singleton 类是无状态的,因为如果我们有任何线程访问它,我们不希望内部变量因为缺乏并发控制而发生变化。

如果你有任何问题,请告诉我!

我已经看到了很多关于保持共享单例 bean 无状态的警告,我想展示一个在支持 bean 的 Web 应用中使用有状态单例的用例。

我有一个管理网络应用程序,根据需要,查询两个独立的系统(一个 CRM 和一个数字资产管理器-DAM)的用户数据,比较记录,并相应地使用其 API 更新 DAM。如果有很多更新,这有时需要很长时间。Web UI 实时显示更新的状态,浏览器每秒使用 ajax 轮询后台 bean,以显示进度条以及它处理了多少个用户帐户。UI 还提供了一个用于启动同步进程的按钮和一个用于停止同步进程的按钮。最初启用了同步按钮,但未呈现停止按钮。用户单击开始按钮后,启动按钮将被禁用,并启用呈现的停止按钮。

当同步处于活动状态时,我希望不同的客户端(不同的用户在键盘上使用不同浏览器中的 web 应用程序)看到相同的状态,即进度条、处理的用户帐户数和按钮状态。这一点很重要,因为当一个进程已经在进行中时,启动第二个同步进程是没有意义的。

这个问题现在已经5岁多了(2019年) ,我希望你已经找到了你想要的答案。但我还是会回复的。 这可能不仅涵盖了您的问题,而且还简要地描述了多线程行为。

首先。单例是编程中使用的一种设计模式,它只用于为 整个应用程序(只有一个 JVM。因为我希望在您的应用程序中只有一个 JVM)。 多线程是一种处理机制,它并发执行任务。 我认为你很困惑,因为你已经知道一个线程是一个逻辑处理位置。对象是一个内存实例。 但是您不了解多线程实际上是如何工作的。 至于你的问题,我将用弹簧框架来解释。

因此,当用户向服务器发送请求时,服务器为每个请求分配一个单独的线程。在春天,bean 默认是单一的。因此,第一个请求开始执行您的单例 bean 的一个方法,在它完成之前,另一个请求来了,它使用另一个线程执行相同的方法。

所以这里发生的是第二个线程不会等待第一个线程完成整个方法的执行。它们并发执行,这意味着第一个请求将运行方法的第一行,然后第二个线程开始运行第一行。也许还有第二行。请注意,当第一个线程执行第一行时,第二个线程不能执行同一行,当第二个线程执行第一行和第二行时,第一个线程不能执行第二行,直到第二个线程完成第二行。

即使我们称之为并发执行,它也根本不并发执行。(一行同时只由一个线程执行) 根据您的问题,在 bean 中定义了两个方法,因此它们是独立的方法。两个线程同时请求两个方法 会同时执行。所以我所描述的不适用于这种情况,如果您的 bean 是为每个请求新创建的,那么这种情况也不会发生,它们将并发执行。