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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25617962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:48:06  来源:igfitidea点击:

How does the singleton Bean serve the concurrent request?

javamultithreadingspringconcurrencymultiprocessing

提问by saravanakumar

I have a question regarding how singleton beans serve concurrent requests in detail.

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

I have searched on StackOverflow regarding this question. This is a sample link from stackoverflow, but I found only high level details. I want full details on how a singleton bean serves concurrent requests and how the system processor will see those requests.

关于这个问题,我在 StackOverflow 上搜索过。这是来自 stackoverflow的示例链接,但我只找到了高级细节。我想要关于单例 bean 如何服务并发请求以及系统处理器如何查看这些请求的完整详细信息。

I have researched regarding concurrent request handling in the system processor online. They said the processor itself has a scheduler and that scheduler will decide which request gets processed.

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

Ok fine. If suppose I have more than one core processor, how does the scheduler handle concurrent requests?

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

Can anyone explain to me the step-by-step process on how a singleton bean will serve concurrent requests in the JVM and system?

谁能向我解释单例 bean 如何在 JVM 和系统中处理并发请求的分步过程?

Let me explain with a concrete example. I have a class like Sports:

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

class Sports {
    public void playFootball() {
    }

    public void playVolleyBall() {
    }
}

Two requests come in. The first request is executing the playFootballmethod on the created singleton instance of class Sports. At the same time, another request is executing the playVolleyBallmethod on the same created singleton instance of class Sports.

两个请求进来了。第一个请求是playFootball在创建的 class 的单例实例上执行方法Sports。同时,另一个请求playVolleyBall在同一个创建的 class 单例实例上执行该方法Sports

How is it possible with a singleton instance?

单例实例怎么可能?

回答by CHowdappaM

Singleton is a bean scope. You have to handle that how to serve for multiple thread access. You can use synchronization or concurrent pakages. Ref: Are Spring singleton beans thread-safe?

Singleton 是一个 bean 作用域。您必须处理如何为多线程访问服务。您可以使用同步或并发包。参考:Spring 单例 bean 线程安全吗?

For concurrent request, single bean will serve for mutliple requests one by one.

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

回答by Ashish Jagtap

To know in details How does the singleton Bean serve the concurrent request? you have to know the following things about Spring Beans

详细了解单例Bean是如何服务并发请求的?关于Spring Beans你必须知道的以下几点

  • Bean scopes

    Spring has different bean scopes (e.g. Prototype, Singleton, etc.) but all these scopes enforce is when the bean is created. For example a "prototype" scoped bean will be created each time this bean is "injected". whereas a "singleton" scoped bean will be created once and shared within the application context.
    "singleton" scoped is default scope of Spring Bean.

  • Creation of Bean

    The whole life cycle of Spring Bean is managed by the Spring Container (i.e. ApplicationContext/BeanFacotry) Spring Container internally refers the bean definition (i.e.XML base ot Annotation based) for creating actual instances of the class defined by that bean definition. now when Spring Container get started it refers to the bean definition and instatiate all the defined bean.

  • Request the Bean.

    Now when your object make a request to the bean then Spring Container will handover the bean which allready initialized.

  • Spring Bean Scope

  • Are Spring objects thread safe?

  • Spring Tutorial 11 - Understanding Bean Scopes

  • Bean 作用域

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

  • Bean的创建

    Spring Bean 的整个生命周期由 Spring Container(即 ApplicationContext/BeanFacotry)管理,Spring Container 在内部引用 bean 定义(即 XML base 或 Annotation based)来创建由该 bean 定义定义的类的实际实例。现在,当 Spring Container 启动时,它会引用 bean 定义并实例化所有定义的 bean。

  • 请求豆。

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

  • Spring Bean 作用域

  • Spring 对象线程安全吗?

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

hope this will help you...

希望能帮到你...

回答by Varun Phadnis

An ideal singleton bean should not keep any state. That means it will not have any variables that store anything specific to the request it is serving.

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

Thus, a singleton bean will simply have stateless code (e.g. controller methods) that can be executed concurrently for multiple requests without any concurrency issues.

因此,单例 bean 将只具有无状态代码(例如控制器方法),可以为多个请求并发执行而没有任何并发​​问题。

For example if following was your singleton bean:

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

@Service
public class Calculator {

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

}

In simple terms, when two "requests" invoke summethod of the bean at the same time, that would mean the summethod would be executed concurrently in two different threads. Hence they will have their own execution context which wont overlap with each other. This would safely allow them to run concurrently.

简单来说,当两个“请求”同时调用sumbean 的sum方法时,这意味着该方法将在两个不同的线程中并发执行。因此,它们将有自己的执行上下文,不会相互重叠。这将安全地允许它们同时运行。

If the same bean was to have state as follows:

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

@Service
public class Calculator {

   int incrementalMultiplier = 0;

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

}

This could cause issues when serving two requests concurrently because the incrementalMultiplieris the object level state that will be shared by the two requests (threads) and hence could produce unexpected results.

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

In short a stateless singleton will be able to serve two requests concurrently because they will be in different threads.

简而言之,无状态单例将能够同时处理两个请求,因为它们将位于不同的线程中。

回答by Devarsh Desai

Saravan Kumar,

萨拉万·库马尔

I understand the motivation behind your question. Before I started working on compilers, I also had a very similar wanting to know the internals of the Java Virtual Machine.

我理解你问题背后的动机。在我开始研究编译器之前,我也有一个非常相似的想了解 Java 虚拟机的内部结构。

First of all, I'm impressed by your question. There needs to be a couple of points of distinctions and understanding in order to solve your question. Firstly: A Singleton pattern, or sometimes even called an anti-pattern, ensures that there is only one instance of this class available to the JVM(Java Virtual Machine). This means we are essentially introducing a global state into an application. I know you understand this, but it is just a point of clarification.

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

Now the internals.

现在是内部结构。

When we create an instance of a class, we are creating an object that is residing in JVM's shared memory. Now, these threads are independently executing code that operates on these instances. Each thread has a working memory, in which it keeps data from the main memory that are shared between all threads. This is where the reference to the Singleton object you have created resides. Essentially what is happening is that the bytecode which was generated and is representative of the singleton object you created is being executed on each one of these threads.

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

Now the internals of how this happens is as follows:

现在这是如何发生的内部结构如下:

Each JVM thread has a private JVM stack, created at the same time as the thread. Now, The JVM has a heap that is shared among all JVM threads. The heap is the runtime data area from which memory for all class instances and arrays is allocated. The heap is created on VM start-up. When your thread requests the singleton instance, it is going to point to a reference in the heap where the bytecode for this Singleton resides. It is going to execute the appropriate code. In your case, it is going to execute the first method for the first request and the second method for the second request. It's able to do this because there are no locks or restriction preventing the compiler from pointing the program counter to the area in the heap where this instance is allocated. The only restriction that the Singleton class puts on the Java Virtual Machine is that it can have only one instance in the heap of this class. That's simply it. Other than that, you can refer to it 100x times from your method, the compiler is going to point to the same bytecode and simply execute it. This is why we typically want the Singleton class to be stateless because if we any thread access it, we don't want internal variables to be mutated because of the lack of concurrency control.

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

Please let me know if you have any questions!

请让我知道,如果你有任何问题!

回答by snakedog

I've seen plenty of admonishments to keep shared singleton beans stateless and I wanted to present a use case where a stateful singleton in a web app backing bean makes sense.

我已经看到很多关于保持共享单例 bean 无状态的警告,我想展示一个用例,其中 Web 应用程序支持 bean 中的有状态单例是有意义的。

I have an administrative web app that, on demand, queries two separate systems (a CRM and a Digital Assets Manager - DAM) for user data, compares the records, and updates the DAM accordingly using its API. This sometimes takes a very long time if there are a lot of updates. The web UI displays the status of the updates in real time, as the browser polls the backing bean using ajax every second to display a progress bar and how many user accounts it has processed. The UI also provides a button to start the sync process and a button to stop it. The sync button is initially enabled and the stop button is not rendered. After the user clicks the start button, the start button is disabled and the stop button rendered enabled.

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

While the sync is active, I want different clients (different users at the keyboard using the web app in their separate browsers) to see the same state, i.e. the progress bar and number of user accounts processed and the button states. This is important because it makes no sense to kick off a second sync process while one is already in process.

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

回答by Tharindu Eranga

This question is 5+ years old by now (2019) and i hope you have found what you are looking for. but i would still post an answer. this may not only cover your question but also described multi-threading behavior in brief.

这个问题现在已经有 5 年以上的历史了(2019 年),我希望您已经找到了您要找的东西。但我仍然会发布一个答案。这可能不仅涵盖您的问题,而且还简要描述了多线程行为。

first of all. the singleton is a design pattern used in programming, which is used to create only one single instance for the entire application (only one for the JVM. as i hope there is only one JVM in your app). multi threading is a processing mechanism. it executes tasks concurrently. i think you are confused because a you've already know that a thread is a logical processing location. and an object is a memory instance. but you did not understand how multi-threading actually works under the hood. as for your question, i will explain this by with spring framework.

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

so when a user send a request to the server, the server dedicate a separate thread for each request. and in spring, the beans are singleton by default. so the first request begins to execute a method of your singleton bean, and before it is finished, an another request comes and it executes the same method by using another thread.

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

so what's happening here is that the second thread will not wait the first one to be finished executing the entire method. they executes concurrently, it means the first request will run the first line of the method and then the second thread begins to run the first line. and maybe second line also. Do note that while the first thread executes the first line, the second thread cannot execute the same line and while the second executes the first line and second line, the first cannot execute the second line until the second thread is finished the second line.

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

even though we call this concurrent execution, it does not execute concurrently at all. (one line is executed by only one thread at same time) according to your question, you are defined two methods in the bean, so they are separate methods. so two threads requesting the two methods at the same time will execute them at the same time. so what i have described will not apply for that scenario and if your beans are created newly for each request then also this will not happen and they execute concurrently.

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