我对单身bean如何详细地处理并发请求有疑问。
我在StackOverflow上搜索过这个问题。这是一个示例link from stackoverflow,但我只找到了高级详细信息。我想要了解单例bean如何处理并发请求以及系统处理器如何看到这些请求的完整细节。
我已经研究过在线系统处理器中的并发请求处理。他们说处理器本身有一个调度程序,调度程序将决定处理哪个请求。
好的。如果假设我有多个核心处理器,那么调度程序如何处理并发请求?
有人可以向我解释一下单例bean如何在JVM和系统中为并发请求提供服务的逐步过程吗?
让我用一个具体的例子来解释。我有一个类Sports
:
class Sports {
public void playFootball() {
}
public void playVolleyBall() {
}
}
有两个请求进入。第一个请求是在创建的类playFootball
的单例实例上执行Sports
方法。同时,另一个请求正在同一个创建的类playVolleyBall
的单例实例上执行Sports
方法。
如何使用单例实例?
答案 0 :(得分:75)
Saravan Kumar,
我理解你的问题背后的动机。在开始编写编译器之前,我也非常想要了解Java虚拟机的内部结构。
首先,我对你的问题印象深刻。为了解决你的问题,需要有几点区分和理解。首先:Singleton模式,有时甚至称为反模式,确保JVM(Java虚拟机)只有一个此类实例可用。这意味着我们基本上将全局状态引入应用程序。我知道你明白这一点,但这只是一个澄清点。
现在是内部人员。
当我们创建一个类的实例时,我们正在创建一个驻留在JVM共享内存中的对象。现在,这些线程独立执行在这些实例上运行的代码。每个线程都有一个工作内存,在该内存中保存所有线程之间共享的主内存数据。这是您创建的Singleton对象的引用所在的位置。基本上发生的事情是,生成的字节码代表您创建的单例对象,正在这些线程中的每一个上执行。
现在这种情况的内部结构如下:
每个JVM线程都有一个私有JVM堆栈,与线程同时创建。现在,JVM有一个在所有JVM线程之间共享的堆。堆是运行时数据区,从中分配所有类实例和数组的内存。堆在VM启动时创建。当您的线程请求单例实例时,它将指向堆中此Singleton的字节码所在的引用。它将执行适当的代码。在您的情况下,它将执行第一个请求的第一个方法和第二个请求的第二个方法。它能够执行此操作,因为没有锁或限制阻止编译器将程序计数器指向分配此实例的堆中的区域。 Singleton类对Java虚拟机的唯一限制是它在该类的堆中只能有一个实例。就是这样。除此之外,你可以从你的方法中引用它100倍,编译器将指向相同的字节码并简单地执行它。这就是为什么我们通常希望Singleton类是无状态的,因为如果我们有任何线程访问它,我们不希望内部变量因为缺乏并发控制而变异。
如果您有任何疑问,请与我们联系!
答案 1 :(得分:16)
理想的单例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
是两个请求(线程)共享的对象级别状态,因此可能会产生意外结果。
简而言之,无状态单例将能够同时处理两个请求,因为它们将位于不同的线程中。
答案 2 :(得分:2)
我已经看到大量的警告让共享单例bean保持无状态,我想提出一个用例,其中Web应用程序支持bean中的有状态单例是有意义的。
我有一个管理网络应用程序,可以根据需要查询用户数据的两个独立系统(CRM和数字资产管理器 - DAM),比较记录,并使用其API相应地更新DAM。如果有大量更新,这有时需要很长时间。 Web UI实时显示更新的状态,因为浏览器每秒使用ajax轮询支持bean以显示进度条以及它已处理的用户帐户数。 UI还提供了一个用于启动同步过程的按钮和一个用于停止同步过程的按钮。最初启用同步按钮并且不显示停止按钮。用户单击开始按钮后,将禁用启动按钮并启用停止按钮。
当同步处于活动状态时,我希望不同的客户端(键盘上的不同用户使用其各自浏览器中的Web应用程序)查看相同的状态,即进度条和处理的用户帐户数以及按钮状态。这很重要,因为在已经进行第二个同步过程时启动第二个同步过程是没有意义的。
答案 3 :(得分:1)
详细了解单例Bean如何为并发请求提供服务? 你必须知道关于Spring Beans的以下内容
Bean范围
Spring有不同的bean作用域(例如Prototype,Singleton等),但所有这些作用域都是在创建bean时实现的。 例如,每次“注入”此bean时,将创建“原型”范围的bean。 而“singleton”作用域bean将在应用程序上下文中创建一次并共享 “singleton”作用域是Spring Bean的默认范围。
创建Bean
Spring Bean的整个生命周期由Spring容器管理(即ApplicationContext / BeanFacotry) Spring Container在内部引用bean定义(即基于XML的基础或基于Annotation)来创建实际实例 由该bean定义定义的类。 现在,当Spring容器启动时,它引用bean定义并实例化所有已定义的bean。
请求Bean。
现在当你的对象向bean发出请求时,Spring Container将移交已经初始化的bean。
<强> Spring Bean Scope 强>
希望这会对你有所帮助......
答案 4 :(得分:0)
这个问题到现在(2019年)已经有5年多了,我希望您找到了所要寻找的东西。但我仍然会发布答案。 这可能不仅涵盖您的问题,而且还简要介绍了多线程行为。
首先。单例是在编程中使用的一种设计模式,该模式仅用于创建一个实例。 整个应用程序(对于JVM只有一个。我希望您的应用程序中只有一个JVM)。 多线程是一种处理机制。它同时执行任务。 我认为您很困惑,因为您已经知道线程是逻辑处理位置。对象是一个内存实例。 但您不了解多线程实际上是如何工作的。 至于您的问题,我将通过spring框架进行解释。
因此,当用户向服务器发送请求时,服务器将为每个请求分配一个单独的线程。在春季,默认情况下,这些豆为单例。因此,第一个请求开始执行您的singleton bean的方法,在此请求完成之前,另一个请求到来,并且它使用另一个线程执行相同的方法。
所以这里发生的是第二个线程不会等待第一个线程完成整个方法的执行。它们同时执行,这意味着第一个请求将运行方法的第一行,然后第二个线程开始运行第一行。也许还有第二行。请注意,虽然第一个线程执行第一行,而第二个线程无法执行同一行,而第二个线程执行第一行和第二行,但第一个线程无法执行第二行,直到第二个线程完成第二行为止。 / p>
即使我们称之为并发执行,它也不会并发执行。 (一行只能由一个线程同时执行) 根据您的问题,您在Bean中定义了两个方法,因此它们是单独的方法。所以两个线程同时请求两个方法 将同时执行它们。因此,我所描述的内容不适用于那种情况,如果您的bean是为每个请求新创建的,那么也不会发生,并且它们会同时执行。
答案 5 :(得分:-1)
Singleton是一个bean范围。您必须处理如何为多线程访问提供服务。您可以使用同步或并发包。参考:Are Spring singleton beans thread-safe?
对于并发请求,单个bean将逐个为多个请求提供服务。